I want to find all possible permutation of two list of strings within a constant length (5). Assume list_1 = ["A"] and list_2 = ["BB"].
All possible combinations are:
A A A A A
A A A BB
A A BB A
A BB A A
BB A A A
A BB BB
BB A BB
BB BB A
I was trying to implement it with the code below, but I am not sure how to define the length 5 for it.
import itertools
from itertools import permutations
list_1 = ["A"]
list_2 = ["BB"]
unique_combinations = []
permut = itertools.permutations(list_1, 5)
for comb in permut:
zipped = zip(comb, list_2)
unique_combinations.append(list(zipped))
print(unique_combinations)
Use recursion:
list_1 = ["A"]
list_2 = ["BB"]
size = 5
strs = list_1 + list_2
res = []
def helper(strs, size, cur, res):
if size == 0:
res.append(cur)
return
if size < 0:
return
for s in strs:
helper(strs, size-len(s), cur+[s], res)
helper(strs, size, [], res)
print(res)
No recursion:
list_1 = ["A"]
list_2 = ["BB"]
size = 5
strs = list_1 + list_2
res = []
q = [[]]
while q:
t = q.pop()
for s in strs:
cur = t + [s]
cursize = len(''.join(cur))
if cursize == size:
res.append(cur)
elif cursize < size:
q.append(cur)
print(res)
You could do the following:
import itertools
unique_combinations = []
permut = itertools.product(["A","B"], repeat=5)
for comb in permut:
l = "".join(comb)
c_bb = l.count("BB")
c_a = l.count("A")
if 2*c_bb + c_a == 5:
unique_combinations.append(l)
print(unique_combinations)
This will give:
['AAAAA', 'AAABB', 'AABBA', 'ABBAA', 'ABBBB', 'BBAAA', 'BBABB', 'BBBBA']
First find all the string-like of length 5 consists of 5 elements, either "A" or "B". Then use string.count to count the occurrences of each substring you are interested in and if it is equal 5 save it.
You can use itertools.product to find all the possible combinations of 'A' and 'BB' (of repeat from 3 to 5, as these are the number of elements in the acceptable answers), and then filter than based on their total length being 5 characters:
import itertools
all_options = []
for i in range(3,6):
all_options += list(itertools.product(['A', 'BB'], repeat=i))
all_options = [i for i in all_options if len(''.join(i)) == 5]
print(all_options)
Output:
[('A', 'BB', 'BB'), ('BB', 'A', 'BB'), ('BB', 'BB', 'A'), ('A', 'A', 'A', 'BB'), ('A', 'A', 'BB', 'A'), ('A', 'BB', 'A', 'A'), ('BB', 'A', 'A', 'A'), ('A', 'A', 'A', 'A', 'A')]
You need a recursive function like this:
def f(words, N, current = ""):
if(len(current)<N):
for i in words:
f(words, N, current+i)
elif(len(current)==N):
print(current)
f(["A", "BB"], 5)
Edit: Unfortunately, this function return duplicates, if two or more words in your list share the same letter. So the correct approach should be to fill a list with all return and then eliminate the duplicates.
Related
I have a string list :
li = ['a', 'b', 'c', 'd']
Using the following code in Python, I generated all the possible combination of characters for list li and got a result of 256 strings.
from itertools import product
li = ['a', 'b', 'c', 'd']
for comb in product(li, repeat=4):
print(''.join(comb))
Say for example, I know the character of the second and fourth position of the string in the list li which is 'b' and 'c'.
So the result will be a set of only 16 strings which is :
abac
abbc
abcc
abdc
bbac
bbbc
bbcc
bbdc
cbac
cbbc
cbcc
cbdc
dbac
dbbc
dbcc
dbdc
How to get this result? Is there a Pythonic way to achieve this?
Thanks.
Edit : My desired size of list li is a to z and the value for repeat is 13. When I tried the above code, compiler throwed memory error!
Use list comprehension:
from itertools import product
li = ['a', 'b', 'c', 'd']
combs = [list(x) for x in product(li, repeat=4)]
selected_combs = [comb for comb in combs if (comb[1] == 'b' and comb[3] == 'c')]
print(["".join(comb) for comb in selected_combs])
# ['abac', 'abbc', 'abcc', 'abdc', 'bbac', 'bbbc', 'bbcc', 'bbdc', 'cbac', 'cbbc', 'cbcc', 'cbdc', 'dbac', 'dbbc', 'dbcc', 'dbdc']
To save memory in case you do not need all the combinations combs, you can simply do:
li = ['a', 'b', 'c', 'd']
selected_combs = [comb for comb in product(li, repeat=4) if (comb[1] == 'b' and comb[3] == 'c')]
print(["".join(comb) for comb in selected_combs])
def permute(s):
out = []
if len(s) == 1:
return s
else:
for i,let in enumerate(s):
for perm in permute(s[:i] + s[i+1:]):
out += [let + perm]
return out
per=permute(['a', 'b', 'c', 'd'])
print(per)
Do you want this?
In a python list, I want to delete all elements repeated less than 'k'.
for example if k == 3 then if our list is:
l = [a,b,c,c,c,a,d,e,e,d,d]
then the output must be:
[c,c,c,d,d,d]
what is a fast way to do that (my data is large), any good pythonic suggestion?
this is what I coded but I don't think it is the fastest and most pythonic way:
from collections import Counter
l = ['a', 'b', 'c', 'c', 'c', 'a', 'd', 'e', 'e', 'd', 'd']
counted = Counter(l)
temp = []
for i in counted:
if counted[i] < 3:
temp.append(i)
new_l = []
for i in l:
if i not in temp:
new_l.append(i)
print(new_l)
You can use collections.Counter to construct a dictionary mapping values to counts. Then use a list comprehension to filter for counts larger than a specified value.
from collections import Counter
L = list('abcccadeedd')
c = Counter(L)
res = [x for x in L if c[x] >=3]
# ['c', 'c', 'c', 'd', 'd', 'd']
A brute-force option would be to get the number of occurrences per item, then filter that output. The collections.Counter object works nicely here:
l = [a,b,c,c,c,a,d,e,e,d,d]
c = Counter(l)
# Counter looks like {'a': 2, 'b': 1, 'c': 3...}
l = [item for item in l if c[item]>=3]
Under the hood, Counter acts as a dictionary, which you can build yourself like so:
c = {}
for item in l:
# This will check if item is in the dictionary
# if it is, add to current count, if it is not, start at 0
# and add 1
c[item] = c.get(item, 0) + 1
# And the rest of the syntax follows from here
l = [item for item in l if c[item]>=3]
I would use a Counter from collections:
from collections import Counter
count_dict = Counter(l)
[el for el in l if count_dict[el]>2]
Any drawback with this option?
l = ['a','b','c','c','c','a','d','e','e','d','d']
res = [ e for e in l if l.count(e) >= 3]
#=> ['c', 'c', 'c', 'd', 'd', 'd']
I want to list all possible words with n letters where the first letter can be a1 or a2, the second can be b1, b2 or b3, the third can be c1 or c2, ... Here's a simple example input-output for n=2 with each letter having 2 alternatives:
input = [["a","b"],["c","d"]]
output = ["ac", "ad", "bc", "bd"]
I tried doing this recursively by creating all possible words with the first 2 letters first, so something like this:
def go(l):
if len(l) > 2:
head = go(l[0:2])
tail = l[2:]
tail.insert(0, head)
go(tail)
elif len(l) == 2:
res = []
for i in l[0]:
for j in l[1]:
res.append(i+j)
return res
elif len(l) == 1:
return l
else:
return None
However, this becomes incredibly slow for large n or many alternatives per letter. What would be a more efficient way to solve this?
Thanks
I think you just want itertools.product here:
>>> from itertools import product
>>> lst = ['ab', 'c', 'de']
>>> words = product(*lst)
>>> list(words)
[('a', 'c', 'd'), ('a', 'c', 'e'), ('b', 'c', 'd'), ('b', 'c', 'e')]`
Or, if you wanted them joined into words:
>>> [''.join(word) for word in product(*lst)]
['acd', 'ace', 'bcd', 'bce']
Or, with your example:
>>> lst = [["a","b"],["c","d"]]
>>> [''.join(word) for word in product(*lst)]
['ac', 'ad', 'bc', 'bd']
Of course for very large n or very large sets of letters (size m), this will be slow. If you want to generate an exponentially large set of outputs (O(m**n)), that will take exponential time. But at least it has constant rather than exponential space (it generates one product at a time, instead of a giant list of all of them), and will be faster than what you were on your way to by a decent constant factor, and it's a whole lot simpler and harder to get wrong.
You can use the permutations from the built-in itertools module to achieve this, like so
>>> from itertools import permutations
>>> [''.join(word) for word in permutations('abc', 2)]
['ab', 'ac', 'ba', 'bc', 'ca', 'cb']
Generating all strings of some length with given alphabet :
test.py :
def generate_random_list(alphabet, length):
if length == 0: return []
c = [[a] for a in alphabet[:]]
if length == 1: return c
c = [[x,y] for x in alphabet for y in alphabet]
if length == 2: return c
for l in range(2, length):
c = [[x]+y for x in alphabet for y in c]
return c
if __name__ == "__main__":
for p in generate_random_list(['h','i'],2):
print p
$ python2 test.py
['h', 'h']
['h', 'i']
['i', 'h']
['i', 'i']
Next Way :
def generate_random_list(alphabet, length):
c = []
for i in range(length):
c = [[x]+y for x in alphabet for y in c or [[]]]
return c
if __name__ == "__main__":
for p in generate_random_list(['h','i'],2):
print p
Next Way :
import itertools
if __name__ == "__main__":
chars = "hi"
count = 2
for item in itertools.product(chars, repeat=count):
print("".join(item))
import itertools
print([''.join(x) for x in itertools.product('hi',repeat=2)])
Next Way :
from itertools import product
#from string import ascii_letters, digits
#for i in product(ascii_letters + digits, repeat=2):
for i in product("hi",repeat=2):
print(''.join(i))
I want to combine two elements in a list based on a given condition.
For example if I encounter the character 'a' in a list, I would like to combine it with the next element. The list:
['a', 'b', 'c', 'a', 'd']
becomes
['ab', 'c', 'ad']
Is there any quick way to do this?
One solution I have thought of is to create a new empty list and iterate through the first list. As we encounter the element 'a' in list 1, we join list1[index of a] and list1[index of a + 1] and append the result to list 2. However I wanted to know if there is any way to do it without creating a new list and copying values into it.
This does not create a new list, just modifies the existing one.
l = ['a', 'b', 'c', 'a', 'd']
for i in range(len(l)-2, -1, -1):
if l[i] == 'a':
l[i] = l[i] + l.pop(i+1)
print(l)
If you don't want to use list comprehension to create a new list (maybe because your input list is huge) you could modify the list in-place:
i=0
while i < len(l):
if l[i]=='a':
l[i] += l.pop(i+1)
i += 1
Use a list comprehension with an iterator on your list. When the current iteratee is a simply join it with the next item from the iterator using next:
l = ['a', 'b', 'c', 'a', 'd']
it = iter(l)
l[:] = [i+next(it) if i == 'a' else i for i in it]
print l
# ['ab', 'c', 'ad']
Well, if you don't want to create a new list so much, here we go:
from itertools import islice
a = list("abcdabdbac")
i = 0
for x, y in zip(a, islice(a, 1, None)):
if x == 'a':
a[i] = x + y
i += 1
elif y != 'a':
a[i] = y
i += 1
try:
del a[i:]
except:
pass
you could use itertools.groupby and group by:
letter follows a or
letter is not a
using enumerate to generate the current index, which allows to fetch the previous element from the list (creating a new list but one-liner)
import itertools
l = ['a', 'b', 'c', 'a', 'd']
print(["".join(x[1] for x in v) for _,v in itertools.groupby(enumerate(l),key=lambda t: (t[0] > 0 and l[t[0]-1]=='a') or t[1]=='a')])
result:
['ab', 'c', 'ad']
This is easy way. Mb not pythonic way.
l1 = ['a', 'b', 'c', 'a', 'd']
do_combine = False
combine_element = None
for el in l1:
if do_combine:
indx = l1.index(el)
l1[indx] = combine_element + el
do_combine = False
l1.remove(combine_element)
if el == 'a':
combine_element = el
do_combine = True
print(l1)
# ['ab', 'c', 'ad']
For example if I have a selection set K
K = ['a','b','c']
and a length N
N = 4
I want to return all possible:
['a','a','a','a']
['a','a','a','b']
['a','a','a','c']
['a','a','b','a']
...
['c','c','c','c']
I can do it with recursion but it is not interesting. Is there a more Pythonic way?
That can be done with itertools.
>>> K = ['a','b','c']
>>> import itertools
>>> N = 4
>>> i = itertools.product(K,repeat = N)
>>> l = [a for a in i]
>>> l[:3]
[('a', 'a', 'a', 'a'), ('a', 'a', 'a', 'b'), ('a', 'a', 'a', 'c')]
EDIT: I realized you actually want product, not combinations_with_replacement. Updated code.