I would like to generate all possible combinations of a given character list with a given length and exclude a few combinations. For example, if I have this list:
chars = ['a', 'b', 'c', '1', '2']
Now I want to exclude character formations of more than 2characters in a row so that combinations like aaaaa or 111111 aren't possible. And I also want the output to be a given length, for example, 5 characters. Is this possible? I thought of itertools
Thanks for any help in advance.
import itertools
chars = ['a', 'b', 'c', '1', '2']
for combination in itertools.product(chars, repeat = 5):
if all(combination.count(x) < 3 for x in combination):
print (combination)
Output:
('c', '1', '1', '2', 'c')
('c', '1', '1', '2', '2')
('c', '1', '2', 'a', 'a')
('c', '1', '2', 'a', 'b')
('c', '1', '2', 'a', 'c')
('c', '1', '2', 'a', '1')
('c', '1', '2', 'a', '2')
('c', '1', '2', 'b', 'a')
('c', '1', '2', 'b', 'b')
('c', '1', '2', 'b', 'c')
('c', '1', '2', 'b', '1')
('c', '1', '2', 'b', '2')
('c', '1', '2', 'c', 'a')
('c', '1', '2', 'c', 'b')
('c', '1', '2', 'c', '1')
('c', '1', '2', 'c', '2')
('c', '1', '2', '1', 'a')
('c', '1', '2', '1', 'b')
('c', '1', '2', '1', 'c')
('c', '1', '2', '1', '2')
('c', '1', '2', '2', 'a')
('c', '1', '2', '2', 'b')
('c', '1', '2', '2', 'c')
('c', '1', '2', '2', '1')
('c', '2', 'a', 'a', 'b')
('c', '2', 'a', 'a', 'c')
('c', '2', 'a', 'a', '1')
('c', '2', 'a', 'a', '2')
('c', '2', 'a', 'b', 'a')
('c', '2', 'a', 'b', 'b')
('c', '2', 'a', 'b', 'c')
('c', '2', 'a', 'b', '1')
('c', '2', 'a', 'b', '2')
('c', '2', 'a', 'c', 'a')
('c', '2', 'a', 'c', 'b')
('c', '2', 'a', 'c', '1')
('c', '2', 'a', 'c', '2')
('c', '2', 'a', '1', 'a')
('c', '2', 'a', '1', 'b')
('c', '2', 'a', '1', 'c')
('c', '2', 'a', '1', '1')
('c', '2', 'a', '1', '2')
('c', '2', 'a', '2', 'a')
('c', '2', 'a', '2', 'b')
('c', '2', 'a', '2', 'c')
('c', '2', 'a', '2', '1')
('c', '2', 'b', 'a', 'a')
('c', '2', 'b', 'a', 'b')
('c', '2', 'b', 'a', 'c')
('c', '2', 'b', 'a', '1')
('c', '2', 'b', 'a', '2')
('c', '2', 'b', 'b', 'a')
('c', '2', 'b', 'b', 'c')
('c', '2', 'b', 'b', '1')
('c', '2', 'b', 'b', '2')
('c', '2', 'b', 'c', 'a')
('c', '2', 'b', 'c', 'b')
('c', '2', 'b', 'c', '1')
('c', '2', 'b', 'c', '2')
('c', '2', 'b', '1', 'a')
('c', '2', 'b', '1', 'b')
('c', '2', 'b', '1', 'c')
('c', '2', 'b', '1', '1')
('c', '2', 'b', '1', '2')
('c', '2', 'b', '2', 'a')
('c', '2', 'b', '2', 'b')
('c', '2', 'b', '2', 'c')
('c', '2', 'b', '2', '1')
('c', '2', 'c', 'a', 'a')
('c', '2', 'c', 'a', 'b')
('c', '2', 'c', 'a', '1')
('c', '2', 'c', 'a', '2')
('c', '2', 'c', 'b', 'a')
('c', '2', 'c', 'b', 'b')
('c', '2', 'c', 'b', '1')
('c', '2', 'c', 'b', '2')
etc...
Related
I have a set of lists and a list with all permutations of the set of lists.
mylist = []
mylist.append(['a', 'b', 'c', 'd', 'e'])
mylist.append(['1', '2', '3', '4', '5'])
mylist.append(['f', 'g', 'h', 'i', 'j'])
# Print all permutations
print(list(itertools.product(*mylist)))
Output
[('a', '1', 'f'), ('a', '1', 'g'), ('a', '1', 'h'), ('a', '1', 'i'), ('a', '1', 'j'), ('a', '2', 'f'), ('a', '2', 'g'), ('a', '2', 'h'), ('a', '2', 'i'), ('a', '2', 'j'), ('a', '3', 'f'), ('a', '3', 'g'), ('a', '3', 'h'), ('a', '3', 'i'), ('a', '3', 'j'), ('a', '4', 'f'), ('a', '4', 'g'), ('a', '4', 'h'), ('a', '4', 'i'), ('a', '4', 'j'), ('a', '5', 'f'), ('a', '5', 'g'), ('a', '5', 'h'), ('a', '5', 'i'), ('a', '5', 'j'), ('b', '1', 'f'), ('b', '1', 'g'), ('b', '1', 'h'), ('b', '1', 'i'), ('b', '1', 'j'), ('b', '2', 'f'), ('b', '2', 'g'), ('b', '2', 'h'), ('b', '2', 'i'), ('b', '2', 'j'), ('b', '3', 'f'), ('b', '3', 'g'), ('b', '3', 'h'), ('b', '3', 'i'), ('b', '3', 'j'), ('b', '4', 'f'), ('b', '4', 'g'), ('b', '4', 'h'), ('b', '4', 'i'), ('b', '4', 'j'), ('b', '5', 'f'), ('b', '5', 'g'), ('b', '5', 'h'), ('b', '5', 'i'), ('b', '5', 'j'), ('c', '1', 'f'), ('c', '1', 'g'), ('c', '1', 'h'), ('c', '1', 'i'), ('c', '1', 'j'), ('c', '2', 'f'), ('c', '2', 'g'), ('c', '2', 'h'), ('c', '2', 'i'), ('c', '2', 'j'), ('c', '3', 'f'), ('c', '3', 'g'), ('c', '3', 'h'), ('c', '3', 'i'), ('c', '3', 'j'), ('c', '4', 'f'), ('c', '4', 'g'), ('c', '4', 'h'), ('c', '4', 'i'), ('c', '4', 'j'), ('c', '5', 'f'), ('c', '5', 'g'), ('c', '5', 'h'), ('c', '5', 'i'), ('c', '5', 'j'), ('d', '1', 'f'), ('d', '1', 'g'), ('d', '1', 'h'), ('d', '1', 'i'), ('d', '1', 'j'), ('d', '2', 'f'), ('d', '2', 'g'), ('d', '2', 'h'), ('d', '2', 'i'), ('d', '2', 'j'), ('d', '3', 'f'), ('d', '3', 'g'), ('d', '3', 'h'), ('d', '3', 'i'), ('d', '3', 'j'), ('d', '4', 'f'), ('d', '4', 'g'), ('d', '4', 'h'), ('d', '4', 'i'), ('d', '4', 'j'), ('d', '5', 'f'), ('d', '5', 'g'), ('d', '5', 'h'), ('d', '5', 'i'), ('d', '5', 'j'), ('e', '1', 'f'), ('e', '1', 'g'), ('e', '1', 'h'), ('e', '1', 'i'), ('e', '1', 'j'), ('e', '2', 'f'), ('e', '2', 'g'), ('e', '2', 'h'), ('e', '2', 'i'), ('e', '2', 'j'), ('e', '3', 'f'), ('e', '3', 'g'), ('e', '3', 'h'), ('e', '3', 'i'), ('e', '3', 'j'), ('e', '4', 'f'), ('e', '4', 'g'), ('e', '4', 'h'), ('e', '4', 'i'), ('e', '4', 'j'), ('e', '5', 'f'), ('e', '5', 'g'), ('e', '5', 'h'), ('e', '5', 'i'), ('e', '5', 'j')]
From above list I want to extract 10 items under the following conditions:
The a should appear 6 times, the b 3 times and the c 1 time.
The 5 should appear 5 times (the rest is random)
The f should appear 2 times and the i should appear 4 times (the rest is random)
Your list of permutations actually contains only combinations. To impose frequencies to your selection of 10, you can pre-fill parts of the combinations with the required values and complete the rest with random values from the remaining elements of the corresponding list. Then shuffle the parts before assembling then into the 10 combinations items:
from random import choices,sample
part0 = sample(['a']*6 + ['b']*3 + choices("cde",k=1) ,10)
part1 = sample(['5']*5 + choices("1234",k=5) ,10)
part2 = sample(['f']*2 + ['i']*4 + choices("ghj",k=4) ,10)
result = list(zip(part0,part1,part2))
Output:
print(*result,sep="\n")
('a', '5', 'i')
('a', '3', 'j')
('b', '5', 'i')
('a', '4', 'g')
('b', '5', 'h')
('b', '5', 'g')
('a', '4', 'f')
('a', '3', 'i')
('a', '1', 'i')
('d', '5', 'f')
\ \ \____ 4 times 'i', 2 times 'f'
\ \________ 5 times '5'
\____________ 6 times 'a', 3 times 'b'
Note that this may produce duplicate combinations. To work around that, you can place the 4 lines in a loop that regenerates the combinations until they are all distinct (with your conditions and a selection of 10 this results in 3.75 attempts on average):
For example:
result = set()
while len(result) != 10:
part0 = sample(['a']*6 + ['b']*3 + choices("cde",k=1) ,10)
part1 = sample(['5']*5 + choices("1234",k=5) ,10)
part2 = sample(['f']*2 + ['i']*4 + choices("ghj",k=4) ,10)
result = set(zip(part0,part1,part2))
If you really want permutations, then you can randomize the position of items produced by zip:
...
result = set(map(lambda c:tuple(sample(c,3)),zip(part0,part1,part2)))
which will then give actual permutations in the result (becoming less likely to have duplicates and only needs 1.22 attempts on average):
('5', 'b', 'i')
('2', 'j', 'a')
('b', 'j', '5')
('g', '2', 'a')
('2', 'f', 'a')
('i', '5', 'a')
('g', '5', 'b')
('i', '1', 'a')
('d', '5', 'f')
('i', '4', 'a')
I have list of objects in Python. Each object contains own list. The list contains some categories of that object. Every list contains exactly 15 elements (could be letter, number or symbol -) eg.
['A', 'A', '1', '-', ... , 'B'] or ['-', 'C', 'X', '-', ... , 'D']
My goal is to find unique values for each category or more precisely of each position in the list, ideally stored in the form of dictionary, for example something like this:
{0: {'A', '-'} 1: {'A', 'C'} ... }
So I need to go through of all objects in the list and save those unique values. Is there a way to do this in elegant, pythonic way?
Thanks for all answers.
you can pair objects position wise with each other with zip
>>> a=['A', 'A', '1', '-', 'B']
>>> b=['-', 'C', 'X', '-', 'D']
>>> list(zip(a,b))
[('A', '-'), ('A', 'C'), ('1', 'X'), ('-', '-'), ('B', 'D')]
>>>
and to get that dictionary from your sample you can add enumerate to the mix
>>> dict(enumerate(zip(a,b)))
{0: ('A', '-'), 1: ('A', 'C'), 2: ('1', 'X'), 3: ('-', '-'), 4: ('B', 'D')}
>>>
and to get the unique such pair you can use set to remove duplicates
>>> c=['A', 'A', '1', '-', 'B', 'A', 'A', '1', '-', 'B']
>>> d=['-', 'C', 'X', '-', 'D', '-', 'C', 'X', '-', 'D']
>>> list(zip(c,d))
[('A', '-'), ('A', 'C'), ('1', 'X'), ('-', '-'), ('B', 'D'), ('A', '-'), ('A', 'C'), ('1', 'X'), ('-', '-'), ('B', 'D')]
>>> set(zip(c,d))
{('A', '-'), ('1', 'X'), ('A', 'C'), ('-', '-'), ('B', 'D')}
>>>
Let's say I have two lists;
a = ['A', 'B', 'C', 'D']
b = ['1', '2', '3', '4']
I know I can get every permutation of these two lists like so:
for r in itertools.product(a, b): print (r[0] + r[1])
But what I'm looking for is every pairwise combination stored in a tuple. So, for example, some combinations would be:
[(A, 1), (B, 2), (C, 3), (D, 4)]
[(A, 1), (B, 3), (C, 2), (D, 4)]
[(A, 1), (B, 4), (C, 3), (D, 2)]
[(A, 1), (B, 3), (C, 4), (D, 2)]
[(A, 1), (B, 2), (C, 4), (D, 3)]
So it would iterate through every possible combination so that no letter has the same number value. I'm at a loss for an efficient way to do this (particularly since I need to scale this to three lists in my actual example)
We can make permutations of one of the lists (for example here the latter one), and then zip each permutation together with the first list, like:
from functools import partial
from itertools import permutations
def pairwise_comb(xs, ys):
return map(partial(zip, xs), permutations(ys))
or in case all subelements should be lists (here these are still iterables that can take a specific shape when you "materialize" these):
from functools import partial
from itertools import permutations
def pairwise_comb(xs, ys):
return map(list, map(partial(zip, xs), permutations(ys)))
For the given sample input, we obtain:
>>> for el in pairwise_comb(a, b):
... print(list(el))
...
[('A', '1'), ('B', '2'), ('C', '3'), ('D', '4')]
[('A', '1'), ('B', '2'), ('C', '4'), ('D', '3')]
[('A', '1'), ('B', '3'), ('C', '2'), ('D', '4')]
[('A', '1'), ('B', '3'), ('C', '4'), ('D', '2')]
[('A', '1'), ('B', '4'), ('C', '2'), ('D', '3')]
[('A', '1'), ('B', '4'), ('C', '3'), ('D', '2')]
[('A', '2'), ('B', '1'), ('C', '3'), ('D', '4')]
[('A', '2'), ('B', '1'), ('C', '4'), ('D', '3')]
[('A', '2'), ('B', '3'), ('C', '1'), ('D', '4')]
[('A', '2'), ('B', '3'), ('C', '4'), ('D', '1')]
[('A', '2'), ('B', '4'), ('C', '1'), ('D', '3')]
[('A', '2'), ('B', '4'), ('C', '3'), ('D', '1')]
[('A', '3'), ('B', '1'), ('C', '2'), ('D', '4')]
[('A', '3'), ('B', '1'), ('C', '4'), ('D', '2')]
[('A', '3'), ('B', '2'), ('C', '1'), ('D', '4')]
[('A', '3'), ('B', '2'), ('C', '4'), ('D', '1')]
[('A', '3'), ('B', '4'), ('C', '1'), ('D', '2')]
[('A', '3'), ('B', '4'), ('C', '2'), ('D', '1')]
[('A', '4'), ('B', '1'), ('C', '2'), ('D', '3')]
[('A', '4'), ('B', '1'), ('C', '3'), ('D', '2')]
[('A', '4'), ('B', '2'), ('C', '1'), ('D', '3')]
[('A', '4'), ('B', '2'), ('C', '3'), ('D', '1')]
[('A', '4'), ('B', '3'), ('C', '1'), ('D', '2')]
[('A', '4'), ('B', '3'), ('C', '2'), ('D', '1')]
This thus results in 24 possible ways to combine this, since the order of 'A', 'B', 'C' and 'D' remains fixed, and the 4 characters can be assigned in 4! ways, or 4! = 4×3×2×1 = 24.
It may be a lot easier than you think. What about:
import itertools
a = ['A', 'B', 'C', 'D']
b = ['1', '2', '3', '4']
for aperm in itertools.permutations(a):
for bperm in itertools.permutations(b):
print(list(zip(aperm, bperm)))
First outputs:
[('A', '1'), ('B', '2'), ('C', '3'), ('D', '4')]
[('A', '1'), ('B', '2'), ('C', '4'), ('D', '3')]
[('A', '1'), ('B', '3'), ('C', '2'), ('D', '4')]
[('A', '1'), ('B', '3'), ('C', '4'), ('D', '2')]
[('A', '1'), ('B', '4'), ('C', '2'), ('D', '3')]
[('A', '1'), ('B', '4'), ('C', '3'), ('D', '2')]
[('A', '2'), ('B', '1'), ('C', '3'), ('D', '4')]
[('A', '2'), ('B', '1'), ('C', '4'), ('D', '3')]
[('A', '2'), ('B', '3'), ('C', '1'), ('D', '4')]
...
(There are 576 lines printed for these two 4-element lists)
Edit: If you want to generalize this to more iterables, you could do something like:
import itertools
a = ['A', 'B', 'C', 'D']
b = ['1', '2', '3', '4']
gens = [itertools.permutations(lst) for lst in (a,b)]
for perms in itertools.product(*gens):
print(list(zip(*perms)))
Which outputs the same thing, but could be easily extended, e.g.
import itertools
a = ['A', 'B', 'C', 'D']
b = ['1', '2', '3', '4']
c = ['W', 'X', 'Y', 'Z']
gens = [itertools.permutations(lst) for lst in (a,b,c)] # add c
for perms in itertools.product(*gens): # no change
print(list(zip(*perms))) # ''
You can use recursion with yield for a no-import solution:
a = ['A', 'B', 'C', 'D']
b = ['1', '2', '3', '4']
def combinations(d, current = []):
if len(current) == 4:
yield current
elif filter(None, d):
for i in d[0]:
_d0, _d1 = [c for c in d[0] if c != i], [c for c in d[1] if c != d[1][0]]
yield from combinations([_d0, _d1] , current+[[i, d[1][0]]])
for i in combinations([a, b]):
print(i)
Output:
[['A', '1'], ['B', '2'], ['C', '3'], ['D', '4']]
[['A', '1'], ['B', '2'], ['D', '3'], ['C', '4']]
[['A', '1'], ['C', '2'], ['B', '3'], ['D', '4']]
[['A', '1'], ['C', '2'], ['D', '3'], ['B', '4']]
[['A', '1'], ['D', '2'], ['B', '3'], ['C', '4']]
[['A', '1'], ['D', '2'], ['C', '3'], ['B', '4']]
[['B', '1'], ['A', '2'], ['C', '3'], ['D', '4']]
[['B', '1'], ['A', '2'], ['D', '3'], ['C', '4']]
[['B', '1'], ['C', '2'], ['A', '3'], ['D', '4']]
[['B', '1'], ['C', '2'], ['D', '3'], ['A', '4']]
[['B', '1'], ['D', '2'], ['A', '3'], ['C', '4']]
[['B', '1'], ['D', '2'], ['C', '3'], ['A', '4']]
[['C', '1'], ['A', '2'], ['B', '3'], ['D', '4']]
[['C', '1'], ['A', '2'], ['D', '3'], ['B', '4']]
[['C', '1'], ['B', '2'], ['A', '3'], ['D', '4']]
[['C', '1'], ['B', '2'], ['D', '3'], ['A', '4']]
[['C', '1'], ['D', '2'], ['A', '3'], ['B', '4']]
[['C', '1'], ['D', '2'], ['B', '3'], ['A', '4']]
[['D', '1'], ['A', '2'], ['B', '3'], ['C', '4']]
[['D', '1'], ['A', '2'], ['C', '3'], ['B', '4']]
[['D', '1'], ['B', '2'], ['A', '3'], ['C', '4']]
[['D', '1'], ['B', '2'], ['C', '3'], ['A', '4']]
[['D', '1'], ['C', '2'], ['A', '3'], ['B', '4']]
[['D', '1'], ['C', '2'], ['B', '3'], ['A', '4']]
Given a multidimensional list (a list of lists) I would like to get all possible combinations of the sub lists items.
For example an input of:
my_list = [
['a', 'b'], ['1', '2'], ['#', '&']
]
Would result in:
result = [
['a'],
['b'],
['1'],
['2'],
['#'],
['&'],
['a', '1'],
['a', '2'],
['a', '#'],
['a', '&']
['b', '1'],
['b', '2'],
['b', '#'],
['b', '&'],
['a', '1', '#'],
['a', '1', '&'],
['a', '2', '#'],
['a', '2', '&'],
...]
I tried using itertools.product(*list) but that results in a combination of all items without the smaller sets of combinations. It seems that itertools.combinations, itertools.permutations, etc don't quite give what I am looking for.
Is there a quick way of doing this?
In that case you first iterate over all possible lengths. For each length you pick all possible combinations of lists, and for each of these combinations you use itertools.product:
def weird_product(*data):
for i in range(1,len(data)+1):
for subdata in itertools.combinations(data,i):
for elem in itertools.product(*subdata):
yield elem
This generates:
>>> list(weird_product(*data))
[('a',), ('b',), ('1',), ('2',), ('#',), ('&',), ('a', '1'), ('a', '2'), ('b', '1'), ('b', '2'), ('a', '#'), ('a', '&'), ('b', '#'), ('b', '&'), ('1', '#'), ('1', '&'), ('2', '#'), ('2', '&'), ('a', '1', '#'), ('a', '1', '&'), ('a', '2', '#'), ('a', '2', '&'), ('b', '1', '#'), ('b', '1', '&'), ('b', '2', '#'), ('b', '2', '&')]
or more elegantly formatted:
>>> list(weird_product(*data))
[('a',),
('b',),
('1',),
('2',),
('#',),
('&',),
('a', '1'),
('a', '2'),
('b', '1'),
('b', '2'),
('a', '#'),
('a', '&'),
('b', '#'),
('b', '&'),
('1', '#'),
('1', '&'),
('2', '#'),
('2', '&'),
('a', '1', '#'),
('a', '1', '&'),
('a', '2', '#'),
('a', '2', '&'),
('b', '1', '#'),
('b', '1', '&'),
('b', '2', '#'),
('b', '2', '&')]
Let us consider
x = ['1', '2', '3', '4', '5']
y = ['a', 'b', 'c', 'd', 'e']
How do I get the required output z?
z = [('1', 'a') , ('b', '2') , ('c', '3') , ('d', '4') , ('e', '5')]
You're looking for zip:
>>> x = ['1', '2', '3', '4', '5']
>>> y = ['a', 'b', 'c', 'd', 'e']
>>> z = zip(x, y)
>>> z
[('1', 'a'), ('2', 'b'), ('3', 'c'), ('4', 'd'), ('5', 'e')]
It's called zip:
z = zip(x, y)