Related
I have an array. I want to generate all permutations from that array, including single element, repeated element, change the order, etc. For example, say I have this array:
arr = ['A', 'B', 'C']
And if I use the itertools module by doing this:
from itertools import permutations
perms = [''.join(p) for p in permutations(['A','B','C'])]
print(perms)
Or using loop like this:
def permutations(head, tail=''):
if len(head) == 0:
print(tail)
else:
for i in range(len(head)):
permutations(head[:i] + head[i+1:], tail + head[i])
arr= ['A', 'B', 'C']
permutations(arr)
I only get:
['ABC', 'ACB', 'BAC', 'BCA', 'CAB', 'CBA']
But what I want is:
['A', 'B', 'C',
'AA', 'AB', 'AC', 'BB', 'BA', 'BC', 'CA', 'CB', 'CC',
'AAA', 'AAB', 'AAC', 'ABA', 'ABB', 'ACA', 'ACC', 'BBB', 'BAA', 'BAB', 'BAC', 'CCC', 'CAA', 'CCA'.]
The result is all permutations from the array given. Since the array is 3 element and all the element can be repetitive, so it generates 3^3 (27) ways. I know there must be a way to do this but I can't quite get the logic right.
A generator that would generate all sequences as you describe (which has infinite length if you would try to exhaust it):
from itertools import product
def sequence(xs):
n = 1
while True:
yield from (product(xs, repeat=n))
n += 1
# example use: print first 100 elements from the sequence
s = sequence('ABC')
for _ in range(100):
print(next(s))
Output:
('A',)
('B',)
('C',)
('A', 'A')
('A', 'B')
('A', 'C')
('B', 'A')
('B', 'B')
('B', 'C')
('C', 'A')
('C', 'B')
('C', 'C')
('A', 'A', 'A')
('A', 'A', 'B')
('A', 'A', 'C')
('A', 'B', 'A')
...
Of course, if you don't want tuples, but strings, just replace the next(s) with ''.join(next(s)), i.e.:
print(''.join(next(s)))
If you don't want the sequences to exceed the length of the original collection:
from itertools import product
def sequence(xs):
n = 1
while n <= len(xs):
yield from (product(xs, repeat=n))
n += 1
for element in sequence('ABC'):
print(''.join(element))
Of course, in that limited case, this will do as well:
from itertools import product
xs = 'ABC'
for s in (''.join(x) for n in range(len(xs)) for x in product(xs, repeat=n+1)):
print(s)
Edit: In the comments, OP asked for an explanation of the yield from (product(xs, repeat=n)) part.
product() is a function in itertools that generates the cartesian product of iterables, which is a fancy way to say that you get all possible combinations of elements from the first iterable, with elements from the second etc.
Play around with it a bit to get a better feel for it, but for example:
list(product([1, 2], [3, 4])) == [(1, 3), (1, 4), (2, 3), (2, 4)]
If you take the product of an iterable with itself, the same happens, for example:
list(product('AB', 'AB')) == [('A', 'A'), ('A', 'B'), ('B', 'A'), ('B', 'B')]
Note that I keep calling product() with list() around it here, that's because product() returns a generator and passing the generator to list() exhausts the generator into a list, for printing.
The final step with product() is that you can also give it an optional repeat argument, which tells product() to do the same thing, but just repeat the iterable a certain number of times. For example:
list(product('AB', repeat=2)) == [('A', 'A'), ('A', 'B'), ('B', 'A'), ('B', 'B')]
So, you can see how calling product(xs, repeat=n) will generate all the sequences you're after, if you start at n=1 and keep exhausting it for ever greater n.
Finally, yield from is a way to yield results from another generator one at a time in your own generator. For example, yield from some_gen is the same as:
for x in some_gen:
yield x
So, yield from (product(xs, repeat=n)) is the same as:
for p in (product(xs, repeat=n)):
yield p
I have list of posiple letter for each letter in a word..and I want to find all possiple words.
for example the input is [[l,b],[e,d],[s,t]] this represent a word of 3 letter wher first letter could be l or b, second letter could be e or d and third letter is s or t. I wont the out put to be the product of these lists [les,let,bet,...and so on]. the list could be any length not only three.
I tried
res = list(map(prod, zip(test_list)))
but I get
[<itertools.product object at 0x0000024F65AEC600>, <itertools.product object at 0x0000024F65AEC640>, <itertools.product object at 0x0000024F65AEC680>, <itertools.product object at 0x0000024F65AEC6C0>]
I tried
word1=list(product(letter[0],letter[1],letter[2]))
it works perfectly but I want the code to accept any length pf list
You don't want to zip the test_list, just pass each element of it as an argument to product using the * operator:
>>> test_list = [['l','b'],['e','d'],['s','t']]
>>> import itertools
>>> list(itertools.product(*test_list))
[('l', 'e', 's'), ('l', 'e', 't'), ('l', 'd', 's'), ('l', 'd', 't'), ('b', 'e', 's'), ('b', 'e', 't'), ('b', 'd', 's'), ('b', 'd', 't')]
If you want the result to be in string form, use join:
>>> [''.join(p) for p in itertools.product(*test_list)]
['les', 'let', 'lds', 'ldt', 'bes', 'bet', 'bds', 'bdt']
I have a sequence of
words=[a,b,c,d]
And I want to find words that can be made out of them in ascending order.
the result list has
[a,ab,abc,abcd,b,bc,bcd,c,cd,d]
how to do it.
I have the code but it has C and python mixed, can someone help me with its python equivalent.
here it goes:
word_list=input("Enter the word")
n=len(word_list)
newlist=[]
for(i=0;i<n;i++)
{
c=''
for(j=i;j<n;j++)
{
c.join(j)
newlist=append(c)
}
}
letters = input("Enter the word")
n = len(letters)
words = [letters[start:end+1] for start in range(n) for end in range(start, n)]
You can do it easily with itertools.combinations
Itertools has some great functions for this kind of thing. itertools.combinations does exactly what you want.
The syntax is:
itertools.combinations(iterable [, length] )
so you can enter your list of words directly as it is an iterable. As you want all the different lengths, you will have to do it in a for-loop to get a list of combinations for all lengths.
So if your words are:
words = ['a', 'b', 'c', 'd']
and you do:
import itertools
itertools.combinations(words, 2)
you will get back an itertools object which you can easily convert to a list with list():
list(itertools.combinations(words, 2))
which will return:
[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
However, if you want a list of all lengths (i.e. including just 'a' and 'abc') then you can just extend the results of each individual list of each list onto another list of all lengths. So something like:
import itertools
words = ['a', 'b', 'c', 'd']
combinations = []
for l in range(1, len(words) + 1):
combinations.extend(list(itertools.combinations(words, l )))
and this will give you the result of:
[('a'), ('b'), ('c'), ('d'), ('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b, 'd'), ('c', 'd'), ('a', 'b', 'c'), ('a', 'b', 'd'), ('a', 'c', 'd'), ('b', 'c', 'd), ('a', 'b', 'c', 'd')]
and if you want these to be more readable (as strings rather than tuples), you can use a list comprehension...
combinations = [''.join(c) for c in combinations]
so now combinations is simply an array of the strings:
['a', 'b', 'c', 'd', 'ab', 'ac', 'ad', 'bc', 'bd', 'cd', 'abc', 'abd', 'acd', 'bcd', 'abcd']
you can use itertools :
>>> import itertools
>>> w=['a','b','c','d']
>>> result=[]
>>> for L in range(1, len(w)+1):
... for subset in itertools.combinations(w, L):
... result.append(''.join(subset))
...
>>> result
['a', 'b', 'c', 'd', 'ab', 'ac', 'ad', 'bc', 'bd', 'cd', 'abc', 'abd', 'acd', 'bcd', 'abcd']
I'm new to programming, and I need some help.
I have a list like this
a=[[('the', 'b'), ('hotel', 'i')],[('the', 'b'), ('staff', 'i')]]
and I'm trying to get rid of the tuple while retaining the data in a list, the outcome should look like this
output=[['the', 'b', 'hotel', 'i'],['the', 'b', 'staff', 'i']]
Thank you so much
You can do the following list comprehension:
>>> [[y for x in i for y in x] for i in a]
[['the', 'b', 'hotel', 'i'], ['the', 'b', 'staff', 'i']]
Note that this has nothing to do with tuples, which because of duck typing are treated the exact same way as lists in a list comprehension. You are essentially doing the operation described in Making a flat list out of list of lists in Python over multiple list items.
I guess you can use:
output = []
for x in a:
output.append([element for tupl in x for element in tupl])
outputs:
[['the', 'b', 'hotel', 'i'], ['the', 'b', 'staff', 'i']]
Here is a "functional"-style variant of #nfn neil's A.
from itertools import repeat
list(map(list, map(sum, a, repeat(()))))
# -> [['the', 'b', 'hotel', 'i'], ['the', 'b', 'staff', 'i']]
This can be accomplished via the sum function:
a=[[('the', 'b'), ('hotel', 'i')],[('the', 'b'), ('staff', 'i')]]
output = [sum(elem, ()) for elem in a]
print(output)
And if it must return a list:
a=[[('the', 'b'), ('hotel', 'i')],[('the', 'b'), ('staff', 'i')]]
output = [sum(map(list,elem), []) for elem in a]
print(output)
I am trying to create the code for the exercise given by my prof. I am to turn piece of string(random) into a list, using lists(guessing .append())
The example that I got was this:
def string_to_list_in_pairs('abcd')
Should return:
['ab', 'bc', 'cd']
I was using the code that I learned in class:
def string_to_list_in_pairs (st):
newL2 = []
for i in range(len(st)):
newL2.append(st[i])
return newL2
but I'm stuck on the part where it turns it into pairs. I know that with this equation I get
['a', 'b', 'c', 'd']
for string 'abcd'
what do I have to add in, in order to make it into pairs? (we didn't learn iterate, prof wants us to use what we learned).
def string_to_list_in_pairs (s):
return [''.join(pair) for pair in zip(s[:-1], s[1:])]
Example
>>> string_to_list_in_pairs('abcd')
['ab', 'bc', 'cd']
How it works
Note how the output looks. The first characters in the three strings are abc which are just the input string without its last character: s[:-1].
Now, look at the last characters in the three strings. They are 'bcd' which are the input string without its first character: s[1:].
We can combine those two with zip and it looks like:
>>> s = 'abcd'
>>> s[:-1], s[1:]
('abc', 'bcd')
>>> zip(s[:-1], s[1:])
[('a', 'b'), ('b', 'c'), ('c', 'd')]
This is almost the right answer. Each tuple in the list has the right characters. The only remaining issue is that it is a tuple and we want a string. To convert a tuple to a string, we apply join. This can be done for each tuple in that list via:
>>> [ ''.join(pair) for pair in [('a', 'b'), ('b', 'c'), ('c', 'd')] ]
['ab', 'bc', 'cd']
Or, putting it all together:
>>> [''.join(pair) for pair in zip(s[:-1], s[1:])]
['ab', 'bc', 'cd']
This just what the function defined above does.
You can use itertools.combinations
>>> import itertools
>>> list(itertools.combinations('abcd', 2))
[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
Two changes are required:
Adding -1 to range(len(st))
Adding +st[i+1] to newL2.append(st[i])
Then:
def string_to_list_in_pairs (st):
newL2 = []
for i in range(len(st)-1):
newL2.append(st[i]+st[i+1])
return newL2
Resulting in:
>>> string_to_list_in_pairs('abcd')
['ab', 'bc', 'cd']
Use itertools
from itertools import combinations
for i in combinations('abcd', 2):
print ''.join(i)
from itertools import combinations
def string_to_list_in_pairs (st):
newL2 = []
for i in combinations(st, 2):
newL2.append(''.join(i))
return newL2
print string_to_list_in_pairs('abcd')
Result:
['ab', 'ac', 'ad', 'bc', 'bd', 'cd']
Using the code you provided you could try the following:
def string_to_list_in_pairs (st):
newL2 = []
for i in range(len(st)-1):
newL2.append(st[i]+st[i+1])
return newL2
The modifications that were made to your code were to reduce the number of times the for loop ran. This was done to ensure that during each iteration you were appending the character that was next to it therefore making a pair.
Here is an example without itertools. The rand_str line creates a random string and the for loop cuts it into two letter pieces:
from random import choice
rand_str="".join([x for x in map(lambda y: choice('ATCG'), range(100))])
duplex_list=[]
for y in range(0,len(rand_str),2):
duplex_list.append(rand_str[y:y+2])
print rand_str
print duplex_list
My answer,
def string_to_list_in_pairs(st):
"""
Compute a list with char pairs from a string """
# For strings with length 1 or 0
if len(st) <= 1:
return list(st)
else:
return [st[i:i+2] for i in range(len(st)-1)]
Results,
>>> string_to_list_in_pairs('')
[]
>>> string_to_list_in_pairs('a')
['a']
>>> string_to_list_in_pairs('ab')
['ab']
>>> string_to_list_in_pairs('abc')
['ab', 'bc']
>>> string_to_list_in_pairs('abcd')
['ab', 'bc', 'cd']
>>> string_to_list_in_pairs('abcde')
['ab', 'bc', 'cd', 'de']