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?
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 have a 26-digit list. I want to print out a list of alphabets according to the numbers. For example, I have a list(consisting of 26-numbers from input):
[0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0]
I did like the output to be like this:
[e,e,l,s]
'e' is on the output 2-times because on the 4-th index it is the 'e' according to the English alphabet formation and the digit on the 4-th index is 2. It's the same for 'l' since it is on the 11-th index and it's digit is 1. The same is for s. The other letters doesn't appear because it's digits are zero.
For example, I give another 26-digit input. Like this:
[1,2,2,3,4,0,3,4,4,1,3,1,4,4,1,0,0,0,0,0,4,2,3,2,2,1]
The output should be:
[a,b,b,c,c,d,d,d,e,e,e,e,g,g,g,h,h,h,h,i,i,i,i,j,k,k,k,l,m,m,m,m,n,n,n,n,o,u,u,u,u,v,v,w,w,w,x,x,y,y,z]
Is, there any possible to do this in Python 3?
You can use chr(97 + item_index) to get the respective items and then multiply by the item itself:
In [40]: [j * chr(97 + i) for i, j in enumerate(lst) if j]
Out[40]: ['ee', 'l', 's']
If you want them separate you can utilize itertools module:
In [44]: from itertools import repeat, chain
In [45]: list(chain.from_iterable(repeat(chr(97 + i), j) for i, j in enumerate(lst) if j))
Out[45]: ['e', 'e', 'l', 's']
Yes, it is definitely possible in Python 3.
Firstly, define an example list (as you did) of numbers and an empty list to store the alphabetical results.
The actual logic to link with the index is using chr(97 + index), ord("a") = 97 therefore, the reverse is chr(97) = a. First index is 0 so 97 remains as it is and as it iterates the count increases and your alphabets too.
Next, a nested for-loop to iterate over the list of numbers and then another for-loop to append the same alphabet multiple times according to the number list.
We could do this -> result.append(chr(97 + i) * my_list[i]) in the first loop itself but it wouldn't yield every alphabet separately [a,b,b,c,c,d,d,d...] rather it would look like [a,bb,cc,ddd...].
my_list = [1,2,2,3,4,0,3,4,4,1,3,1,4,4,1,0,0,0,0,0,4,2,3,2,2,1]
result = []
for i in range(len(my_list)):
if my_list[i] > 0:
for j in range(my_list[i]):
result.append(chr(97 + i))
else:
pass
print(result)
An alternative to the wonderful answer by #Kasramvd
import string
n = [0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0]
res = [i * c for i, c in zip(n, string.ascii_lowercase) if i]
print(res) # -> ['ee', 'l', 's']
Your second example produces:
['a', 'bb', 'cc', 'ddd', 'eeee', 'ggg', 'hhhh', 'iiii', 'j', 'kkk', 'l', 'mmmm', 'nnnn', 'o', 'uuuu', 'vv', 'www', 'xx', 'yy', 'z']
Splitting the strings ('bb' to 'b', 'b') can be done with the standard schema:
[x for y in something for x in y]
Using a slightly different approach, which gives the characters individually as in your example:
import string
a = [0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0]
alphabet_lookup = np.repeat(np.arange(len(a)), a)
letter_lookup = np.array(list(string.ascii_lowercase))
res = letter_lookup[alphabet_lookup]
print(res)
To get
['e' 'e' 'l' 's']
This question already has answers here:
Wrapping around on a list when list index is out of range
(3 answers)
Closed 5 years ago.
Title may be confusing but I don't know how to express myself any better. What I have is a list that looks something like this:
myList = ['a', 'b', 'c', 'd', 'e', 'f']
what I want to do is a for loop that, for example, starts at index 3, so 'd' and then goes to the end but at the end of the list insted of finishing goes back to the beginning, goes through 'a','b','c' and then finishes at 'd'. I tried doing it like this with a while loop:
index = 3
while index != 2:
if index == len(a):
index = 0
else:
pass
print(a[index])
index += 1
This sorta worked but it will never print out 'c' but if I put 3 as index the loop will never even start. Is there a more elegant solution to do something like this?
You can use the modulus operator against the length of the string
def offset_print(s, offset):
for i in range(len(s)):
print(s[(i+offset) % len(s)])
Example
>>> offset_print('hello', 2)
l
l
o
h
e
So, definitely like #CoryKramer's approach, but this one doesn't require you to calculate the length of the iterator:
def run_offset(lst, fn, offset=0):
base = []
for item in lst:
if offset > 0:
# append the original list until you're no longer dealing with an offset
base.append(item)
offset -= 1
continue
# just yield the current value
yield item
# iterate through the indexes 0... offset
for item in base:
yield item
> list(run_offset('abcd', print, 2))
['c', 'd', 'a', 'b']
Not the most efficient -- but if your list is short and you just want pure simplicity, you can shift your list;
shifted = my_list[n:] + my_list[:n]
for item in shifted:
# do stuff here
... Or use a deque;
>>> import collections
>>> dq = collections.deque(['a', 'b', 'c', 'd'])
>>> dq
deque(['a', 'b', 'c', 'd'])
>>> dq.rotate(2)
>>> dq
deque(['c', 'd', 'a', 'b'])
Using itertools.cycle also works here:
from itertools import cycle
def offset_print(s, offset):
it = cycle(s)
items = [next(it) for i in range(len(s) + offset)]
for x in items[offset:]:
print(x)
Which Outputs:
>>> offset_print(['a', 'b', 'c', 'd', 'e', 'f'], 2)
c
d
e
f
a
b
I have a list that looks like:
A
B
C
D
E
F
G
How do I solve this to find all combinations for 3 digits. The same letter cannot be used in same row.
ABC
ABD
ABE
ABF
ABG
AGB
E.g something like...:
x = ['a','b','c','d','e']
n = 3
import itertools
aa = [list(comb) for i in range(1, n+2) for comb in itertools.combinations(x, i)]
print(aa)
This does not give desired input:
[['a'], ['b'], ['c'], ['d'], ['e'], ['a', 'b'], ['a', 'c'], ['a', 'd'], ['a', 'e'], ['b', 'c'], ['b', 'd'], ['b', 'e'], ['c'
The Python Standard Library itertools already has the functionality you are trying to implement. Also you are using it in your code (funnily).
itertools.combinations(a,3) returns all 3-combinations of the a. To convert that to "list of list" you should use .extend() as follows;
x = ['a','b','c','d','e']
n = 3
import itertools
permutations = []
combinations = []
combinations.extend(itertools.combinations(x,n))
permutations.extend(itertools.permutations(x,n))
print("Permutations;", permutations)
print("\n")
print("Combinations;", combinations)
Additionally, I suggest you to search on "Combination, Permutation Difference". As I understood from your question; permutation is what you want. (If you run the code I shared, you will understand the difference easliy.)
To understand how the solution process works, try the following:
# get all combinations of n items from given list
def getCombinations(items, n):
if len(items) < n: return [] # need more items than are remaining
if n == 0: return [''] # need no more items, return the combination of no items
[fst, *rst] = items
# all combinations including the first item in the list
including = [fst + comb for comb in getCombinations(rst, n-1)]
# all combinations excluding the first item in the list
excluding = getCombinations(rst, n)
both = including + excluding
return both
x = ['a','b','c','d','e']
n = 3
print(getCombinations(x, n))
# ['abc', 'abd', 'abe', 'acd', 'ace', 'ade', 'bcd', 'bce', 'bde', 'cde']
combinations works on strings not lists, so you should first turn it into a string using: ''.join(x)
from itertools import combinations
x = ['a', 'b', 'c', 'd', 'e']
n = 3
aa = combinations(''.join(x), n)
for comb in aa:
print(''.join(comb))
OUTPUT
abc
abd
abe
acd
ace
ade
bcd
bce
bde
cde
Or as a one-liner:
[''.join(comb) for comb in combinations(''.join(x), n)]