2
import itertools
a = [[2, 3], [3, 4]]
b = [[5, 6], [7, 8], [9, 10]]
c = [[11, 12], [13, 14]]
d = [[15, 16], [17, 18]]
e = [[12,16],[13,17],[14,18],[15,19]]

q=[]
q=list(itertools.combinations((a, b, b,c, c, d,e),7)
print q

How would I go about using the combination function from itertools properly to use list a one time, b 2 times without replacement, c 2 times without replacement, and d and e one time each?

[[[2, 3],[5, 6],[7, 8],[11, 12],[13, 14],[15, 16],[12,16]], 
[[2, 3],[5, 6],[7, 8],[11, 12],[13, 14],[15, 16],[13,17]],
[[2, 3],[5, 6],[7, 8],[11, 12],[13, 14],[15, 16],[14,18]],
[[2, 3],[5, 6],[7, 8],[11, 12],[13, 14],[15, 16],[15,19]], 
[[2, 3],[5, 6],[7, 8],[11, 12],[13, 14],[15, 16],[12,16]],...
[[3, 4],[7, 8],[9, 10],[11, 12], [13, 14],[17, 18],[15,19]]]
William Bernard
  • 359
  • 4
  • 15
  • 1
    Are the two draws from `b` with or without replacement? – Neal Fultz Sep 15 '16 at 20:35
  • 1
    I'm not sure I understand what you want here (can you give the first few example outputs or something to be sure?), but if you wrap `itertools.combinations` in `list` for a decent number of inputs, you're almost guaranteed to blow your memory. The number of outputs grows at roughly `O(n!)` (factorial growth); you're usually expected to iterate the combinations one by one, not store them all at once. – ShadowRanger Sep 15 '16 at 20:35
  • Without replacement, – William Bernard Sep 15 '16 at 20:39
  • 1
    Could you show us the expected output? – Ted Klein Bergman Sep 15 '16 at 20:46

3 Answers3

1

Updated given clarification of expected output:

You want itertools.product:

itertools.product(a, b, b, c, c, c, c, d, e)

Which will pick one element from each of its arguments on each iteration, cycling the rightmost element the fastest, leftmost slowest.

You can use extended argument unpacking to express the repetition of certain arguments a little more obviously in Python 3:

itertools.product(a, *[b]*2, *[c]*4, d, e)

Or use tobias_k's solution for more general repetition of sequences (that will also work on Py2).

Community
  • 1
  • 1
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
1

It seems like you are looking for a combination of combinations and product: Use combinations to get the possible combinations without replacement for the repeated lists, then use product to combine all those combinations. You can put the lists and counts in two lists, zip those lists, and use a generator expression to get all the combinations.

from itertools import product, combinations, chain
lists = [a,b,c,d,e]
counts = [1,2,2,1,1]
combs = product(*(combinations(l, c) for l, c in zip(lists, counts)))

For this example, the combs generator has 48 elements, among others:

[(([2, 3],), ([5, 6], [7, 8]), ([11, 12], [13, 14]), ([15, 16],), ([12, 16],)),
 ...
 (([2, 3],), ([5, 6], [7, 8]), ([11, 12], [13, 14]), ([17, 18],), ([15, 19],)),
 (([2, 3],), ([5, 6], [9, 10]),([11, 12], [13, 14]), ([15, 16],), ([12, 16],)),
 ...
 (([3, 4],), ([5, 6], [7, 8]), ([11, 12], [13, 14]), ([15, 16],), ([12, 16],)),
 ...
 (([3, 4],), ([5, 6], [7, 8]), ([11, 12], [13, 14]), ([17, 18],), ([15, 19],)),
 ...
 (([3, 4],), ([7, 8], [9, 10]),([11, 12], [13, 14]), ([17, 18],), ([15, 19],))]

If you want flattened lists, just chain them:

>>> combs = (list(chain(*p)) for p in product(*(combinations(l, c) for l, c in zip(lists, counts))))
>>> list(combs)
[[[2, 3], [5, 6], [7, 8], [11, 12], [13, 14], [15, 16], [12, 16]],
 ...
 [[3, 4], [7, 8], [9, 10], [11, 12], [13, 14], [17, 18], [15, 19]]]
Community
  • 1
  • 1
tobias_k
  • 81,265
  • 12
  • 120
  • 179
1

What your are trying to achieve is the Cartesian product of input iterables and not the combinations of the item present in the list. Hence you have to use itertools.product() instead.

In case repetition is allowed among the lists which used more than once, answer is simple:

>>> import itertools
>>> a = [1,2]
>>> b = [3,4]
>>> [i for i in itertools.product(a, b, b)]
[(1, 3, 3), (1, 3, 4), (1, 4, 3), (1, 4, 4), (2, 3, 3), (2, 3, 4), (2, 4, 3), (2, 4, 4)]

But in case repetition is not allowed within the same lists, it will become little nasty and you need to combine the above answer with combinations() and chain() (same as mentioned by tobias_k). This code will give the list of all combinations:

>>> from itertools import chain, product, combinations
>>> lists, counts = [a, b], [1, 2]  # to track that a is to be used once, and b twice
>>> list(list(chain(*p)) for p in product(*(combinations(l, c) for l, c in zip(lists, counts))))
[[1, 3, 4], [2, 3, 4]]

However, in case you need permutations instead of combinations, you have to update the above code with permutations():

>>> from itertools import chain, product, permutations
>>> list(list(chain(*p)) for p in product(*(permutations(l, c) for l, c in zip(lists, counts))))
[[1, 3, 4], [1, 4, 3], [2, 3, 4], [2, 4, 3]]
Community
  • 1
  • 1
Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
  • 1
    Not entirely clear from the question, but I think then the last line in the expected output should contain `[13, 14], [11, 12]` instead of `[11, 12], [13, 14]`. – tobias_k Sep 15 '16 at 21:21
  • 1
    @tobias_k On looking at his sample output, I believe he needs cartesian product of the lists. Updated the answer with simple example. And I agree with you, the input params OP provided are too huge and gives no clear insight of his intention. Simpler example would be helpful – Moinuddin Quadri Sep 15 '16 at 21:29
  • order doesnt matter – William Bernard Sep 15 '16 at 22:12
  • 1
    @WilliamBernard : In that case it is @ tobias_k answer you should be marked as accepted. As I have mentioned this after he answered – Moinuddin Quadri Sep 15 '16 at 22:13
  • 1
    @WilliamBernard: It was not cleared from the sample you provided in the question. So, I mentioned all the possible solutions :P – Moinuddin Quadri Sep 15 '16 at 22:14
  • I apologize, but without replacement is an important distinction I didnt mention as well as order not mattering – William Bernard Sep 15 '16 at 22:16