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
How do I remove all 'd' and 'e'
abc = [('a','b','c','d','e'), ('a','b','c','d','e'),
('a','b','c','d','e'), ('a','b','c','d','e')]
abc.remove('d')
ValueError: list.remove(x): x not in list
abc.remove('d', 'e')
TypeError: remove() takes exactly one argument (2 given)
finalList = []
for l in abc:
finalList.append([i[3] for i in l])
IndexError: string index out of range
You can use a nested list comprehension to check if any of the sub elements are in your "blacklist" and keep the rest.
>>> [tuple(i for i in sub if i not in {'d', 'e'}) for sub in abc]
[('a', 'b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'c')]
You cannot remove an element from a tuple. However, the following procedure can solve your problem.
abc = [('a','b','c','d','e'), ('a','b','c','d','e'), ('a','b','c','d','e'), ('a','b','c','d','e')]
l = [] // Creating an empty list
// Appending all tuples of abc in l as LISTS
for item in abc:
l.append(list(item))
// Removing the unnecessary elements
for item in l:
item.remove('d')
item.remove('e')
print(l)
l = [('a','b','c','d','e'), ('a','b','c','d','e'),
('a','b','c','d','e'), ('a','b','c','d','e')]
print ([tuple(s for s in x if s not in ['d','e']) for x in l])
Output:
[('a', 'b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'c')]
Here's my code:
import itertools
def permutations(string):
if len(string) <= 1:
return string
return itertools.permutations(string)
If 'ab' is input, it returns [('a', 'b'), ('b', 'a')]
Is there any way I can combine the tuple items and then change the tuple into a list item such that it returns: ['ab', 'ba']?
strings are seen as iterables, and combined into tuples by itertools.permutations.
To convert them back as strings, just use str.join on the tuples (would work on a longer permutation):
["".join(x) for x in [('a', 'b'), ('b', 'a')]]
in your case:
["".join(x) for x in itertools.permutations(string)]
[a+b for a,b in itertools.permutations(string)]
with map:
map(lambda(x):''.join(x), itertools.permutations(string))
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']
I wish to have a function, subset(("A","b","C","D"),3), which gives the following output:
("A","b","C")
("A","b","D")
("A","C","D")
("b","C","D")
How might I do this in python 3?
The itertools.combinations function was built explicitly for this purpose:
>>> from itertools import combinations
>>> list(combinations(("A","b","C","D"), 3))
[('A', 'b', 'C'), ('A', 'b', 'D'), ('A', 'C', 'D'), ('b', 'C', 'D')]
>>>
From the docs:
itertools.combinations(iterable, r)
Return r length subsequences of elements from the input iterable.