I'm trying to sort a list containing only lower case letters by using the string :
alphabet = "abcdefghijklmnopqrstuvwxyz".
that is without using sort, and with O(n) complexity only.
I got here:
def sort_char_list(lst):
alphabet = "abcdefghijklmnopqrstuvwxyz"
new_list = []
length = len(lst)
for i in range(length):
new_list.insert(alphabet.index(lst[i]),lst[i])
print (new_list)
return new_list
for this input :
m = list("emabrgtjh")
I get this:
['e']
['e', 'm']
['a', 'e', 'm']
['a', 'b', 'e', 'm']
['a', 'b', 'e', 'm', 'r']
['a', 'b', 'e', 'm', 'r', 'g']
['a', 'b', 'e', 'm', 'r', 'g', 't']
['a', 'b', 'e', 'm', 'r', 'g', 't', 'j']
['a', 'b', 'e', 'm', 'r', 'g', 't', 'h', 'j']
['a', 'b', 'e', 'm', 'r', 'g', 't', 'h', 'j']
looks like something goes wrong along the way, and I can't seem to understand why.. if anyone can please enlighten me that would be great.
You are looking for a bucket sort. Here:
def sort_char_list(lst):
alphabet = "abcdefghijklmnopqrstuvwxyz"
# Here, create the 26 buckets
new_list = [''] * len(alphabet)
for letter in lst:
# This is the bucket index
# You could use `ord(letter) - ord('a')` in this specific case, but it is not mandatory
index = alphabet.index(letter)
new_list[index] += letter
# Assemble the buckets
return ''.join(new_list)
As for complexity, since alphabet is a pre-defined fixed-size string, searching a letter in it is requires at most 26 operations, which qualifies as O(1). The overall complexity is therefore O(n)
Related
I wrote my code and it's working perfectly but the output doesn't really look good. I was it to look more presentable/systematic. How do I do that? This is the kind of result I'm currently getting:
and this is the type of result I want:
This code is basically to find permutations of whatever is inputted.
def permutations(aSet):
if len(aSet) <= 1: return aSet
all_perms = []
first_element = aSet[0:1]
subset = aSet[1:]
partial = permutations(subset)
for permutation in partial:
for index in range(len(aSet)):
new_perm = list(permutation[:index])
new_perm.extend(first_element)
new_perm.extend(permutation[index:])
all_perms.append(new_perm)
return all_perms
I can't figure out what to try.
You can sort the output array with a custom key function. Here keyFunc converts a permutaiton (list of characters) into a single string to perform lexicographic sorting.
from pprint import pprint
# insert your function here
def keyFunc(char_list):
return ''.join(char_list)
chars = list('dog')
permutation = permutations(chars)
permutation.sort(key=keyFunc)
pprint(permutation)
Output:
[['d', 'g', 'o'],
['d', 'o', 'g'],
['g', 'd', 'o'],
['g', 'o', 'd'],
['o', 'd', 'g'],
['o', 'g', 'd']]
Here's a way to order the permutations differently: for each item in the input array, take it out of the array, find all permutations of the remaining subarray, then prepend this item to each permutation of this subarray. This has the effect of placing permutations with similar prefixes together.
from pprint import pprint
def permutations2(chars):
if len(chars) <= 1: return [chars]
all_perms = []
for idx, char in enumerate(chars):
subarr = chars[:idx] + chars[idx+1:]
subperms = permutations2(subarr)
for subperm in subperms:
new_perm = [char] + subperm
all_perms.append(new_perm)
return all_perms
chars = list('dog')
pprint(permutations2(chars))
Result:
[['d', 'o', 'g'],
['d', 'g', 'o'],
['o', 'd', 'g'],
['o', 'g', 'd'],
['g', 'd', 'o'],
['g', 'o', 'd']]
Given a 2d matrix such as [[a,b,c],[d,e,f]...]], I want to perform a Cartesian product of the matrix so I can determine all the possible combinations.
For this particular constraint, when I am using a 2d matrix with 12 different subsets, it uses more than the 16 megabytes of allotted memory I have. There are three values in each subset, so I would have 312 different combinations.
The cartesian product function that I am using is:
def cartesian_iterative(pools):
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
return result
I would like to know how I could reduce memory consumption without using any external libraries. An example 2d array I would working with is [['G', 'H', 'I'], ['M', 'N', 'O'], ['D', 'E', 'F'], ['D', 'E', 'F'], ['P', 'R', 'S'], ['D', 'E', 'F'], ['M', 'N', 'O'], ['D', 'E', 'F'], ['D', 'E', 'F'], ['M', 'N', 'O'], ['A', 'B', 'C'], ['D', 'E', 'F']]
EDIT:
For reference, a link to the problem statement can be found here Problem Statement. Here is the link to the file of possible names Acceptable Names.
The final code:
with open('namenum.in','r') as fin:
num = str(fin.readline().strip()) #the number being used to determine all combinations
numCount = []
for i in range(len(num)):
numCount.append(dicti[num[i]]) #creates a 2d array where each number in the initial 'num' has a group of three letters
def cartesian_iterative(pools): #returns the product of a 2d array
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
return result
pos = set() #set of possible names
if len(num) == 12: #only uses more than the allocated memory when the num is 12 digits long.
'''
This optimization allows the product to only calculate 2 * 3^6 values, instead of 3**12. This saves a lot of memory
'''
rights = cartesian_iterative(numCount[6:])
for left in cartesian_iterative(numCount[:6]):
for right in rights:
a = ''.join(left+right)
if a in names:
pos.add(a) #adding name to set
else: #if len(num) < 12, you do not need any other optimizations and can just return normal product
for i in cartesian_iterative(numCount):
a = ''.join(i)
if a in names:
pos.add(a)
pos = sorted(pos)
with open('namenum.out','w') as fout: #outputting all possible names
if len(pos) > 0:
for i in pos:
fout.write(i)
fout.write('\n')
else:
fout.write('NONE\n')
You could use that function on left and right half separately. Then you'd only have 2×36 combinations instead of 312. And they're half as long, somewhat even canceling that factor 2.
for left in cartesian_iterative(pools[:6]):
for right in cartesian_iterative(pools[6:]):
print(left + right)
Output:
['G', 'M', 'D', 'D', 'P', 'D', 'M', 'D', 'D', 'M', 'A', 'D']
['G', 'M', 'D', 'D', 'P', 'D', 'M', 'D', 'D', 'M', 'A', 'E']
['G', 'M', 'D', 'D', 'P', 'D', 'M', 'D', 'D', 'M', 'A', 'F']
['G', 'M', 'D', 'D', 'P', 'D', 'M', 'D', 'D', 'M', 'B', 'D']
...
To be faster, compute the right combinations only once:
rights = cartesian_iterative(pools[6:])
for left in cartesian_iterative(pools[:6]):
for right in rights:
print(left + right)
This question already has an answer here:
How can I group equivalent items together in a Python list?
(1 answer)
Closed 3 years ago.
I want to split a list sequence of items in Python or group them if they are similar.
I already found a solution but I would like to know if there is a better and more efficient way to do it (always up to learn more).
Here is the main goal
input = ['a','a', 'i', 'e', 'e', 'e', 'i', 'i', 'a', 'a']
desired_ouput = [['a','a'], ['i'], ['e','e', 'e'], ['i', 'i'], ['a', 'a']
So basically I choose to group by similar neighbour.I try to find a way to split them if different but get no success dooing it.
I'm also keen on listening the good way to expose the problem
#!/usr/bin/env python3
def group_seq(listA):
listA = [[n] for n in listA]
for i,l in enumerate(listA):
_curr = l
_prev = None
_next= None
if i+1 < len(listA):
_next = listA[i+1]
if i > 0:
_prev = listA[i-1]
if _next is not None and _curr[-1] == _next[0]:
listA[i].extend(_next)
listA.pop(i+1)
if _prev is not None and _curr[0] == _prev[0]:
listA[i].extend(_prev)
listA.pop(i-1)
return listA
listA = ['a','a', 'i', 'e', 'e', 'e', 'i', 'i', 'a', 'a']
output = group_seq(listA)
print(listA)
['a', 'a', 'i', 'e', 'e', 'e', 'i', 'i', 'a', 'a']
print(output)
[['a', 'a'], ['i'], ['e', 'e', 'e'], ['i', 'i'], ['a', 'a']]
I think itertool.groupby is probably the nicest way to do this. It's flexible and efficient enough that it's rarely to your advantage to re-implement it yourself:
from itertools import groupby
inp = ['a','a', 'i', 'e', 'e', 'e', 'i', 'i', 'a', 'a']
output = [list(g) for k,g in groupby(inp)]
print(output)
prints
[['a', 'a'], ['i'], ['e', 'e', 'e'], ['i', 'i'], ['a', 'a']]
If you do implement it yourself, it can probably be much simpler. Just keep track of the previous value and the current list you're appending to:
def group_seq(listA):
prev = None
cur = None
ret = []
for l in listA:
if l == prev: # assumes list doesn't contain None
cur.append(l)
else:
cur = [l]
ret.append(cur)
prev = l
return ret
I have this list which contains letters, and I need to check if a pre-determined word located in another list is horizontally inside this list of letters.
i.e.:
mat_input = [['v', 'e', 'd', 'j', 'n', 'a', 'e', 'o'], ['i', 'p', 'y', 't', 'h', 'o', 'n', 'u'], ['s', 'u', 'e', 'w', 'e', 't', 'a', 'e']]
words_to_search = ['python', 'fox']
I don't need to tell if a word was not found, but if it was I need to tell which one.
My problem is that so far I've tried to compare letter by letter, in a loop similar to this:
for i in range(n): # n = number of words
for j in range(len(word_to_search[i])): # size of the word I'm searching
for k in range(h): # h = height of crossword
for m in range(l): # l = lenght of crossword
But it's not working, inside the last loop I tried several if/else conditions to tell if the whole word was found. How can I solve this?
You can use str.join:
mat_input = [['v', 'e', 'd', 'j', 'n', 'a', 'e', 'o'], ['i', 'p', 'y', 't', 'h', 'o', 'n', 'u'], ['s', 'u', 'e', 'w', 'e', 't', 'a', 'e']]
words_to_search = ['python', 'fox']
joined_input = list(map(''.join, mat_input))
results = {i:any(i in b or i in b[::-1] for b in joined_input) for i in words_to_search}
Output:
{'python': True, 'fox': False}
I'd start by joining each sublist in mat_input into one string:
mat_input_joined = [''.join(x) for x in mat_input]
Then loop over your words to search and simply use the in operator to see if the word is contained in each string:
for word_to_search in words_to_search:
result = [word_to_search in x for x in mat_input_joined]
print('Word:',word_to_search,'found in indices:',[i for i, x in enumerate(result) if x])
Result:
Word: python found in indices: [1]
Word: fox found in indices: []
I am wondering why this piece of code:
wordlist = ['cat','dog','rabbit']
letterlist=[]
for aword in wordlist:
for aletter in aword:
if aletter not in letterlist:
letterlist.append(aletter)
print(letterlist)
prints ['c', 'a', 't', 'd', 'o', 'g', 'r', 'b', 'i']
while this code:
wordlist = ['cat','dog','rabbit']
letterlist=[]
for aword in wordlist:
for aletter in aword:
letterlist.append(aletter)
print(letterlist)
prints ['c', 'a', 't', 'd', 'o', 'g', 'r', 'a', 'b', 'b', 'i', 't']
I don't understand how the code is being computed and doesn't spell out all of 'rabbit' and/or why it spells out 'r', 'b', 'i'? Anyone know what's going on?
You are adding each unique letter to letterlist with this if block:
if aletter not in letterlist:
letterlist.append(aletter)
If the letter has already been seen, it does not get appended again. That means the second time you see a (in 'rabbit'), the second b (in 'rabbit') and the second and third time you see t, they aren't added to the list.
This part of the code if aletter not in letterlist: checks if the letter has already been added to the list. If it does, you wont add it again.
So basically you wont add any repeated characters. That's why the output is ['c', 'a', 't', 'd', 'o', 'g', 'r', 'b', 'i'] . No repeated letters there.
The second piece of code just iterates the whole list and appends to letterlist no matter what. That's why all letters are added, and you get ['c', 'a', 't', 'd', 'o', 'g', 'r', 'a', 'b', 'b', 'i', 't'] as result.