2

I want to get the combinations of a list of list, for example

[['a0', 'a1'], ['b0', 'b1'], ['c0', 'c1', 'c2']]

I can use list(itertools.product(*listOfTuples)) and get

[('a0', 'b0', 'c0'), ('a0', 'b0', 'c1'), ('a0', 'b0', 'c2')... ('a1', 'b1', 'c2')]

How would I get a list with the possible combinations of length 2? For example:

[('a0', 'b0'), ('a0', 'c0'), ('b0', 'c0')...
  • Should all the elements of the sublists be unique relative to the initial letters? – Ajax1234 May 07 '18 at 02:42
  • 1
    Is `('a0', 'a1')` a valid combination of length 2, i.e. 2 from the same original group? – AChampion May 07 '18 at 02:54
  • This is straightforwardly a matter of getting each pair of lists that you want to feed to `itertools.product`, and then iteratively doing so. Those pairs are `itertools.combinations` of the list of lists. I have accordingly closed this as a duplicate. – Karl Knechtel Feb 28 '23 at 20:59

2 Answers2

3

You can just call itertools.combinations() with r=2 to get all pairs of each triple and then flatten, e.g.:

In []:
import itertools as it
[t for x in it.product(*s) for t in it.combinations(x, r=2)]

Out[]:
[('a0', 'b0'), ('a0', 'c0'), ('b0', 'c0'), ('a0', 'b0'), ('a0', 'c1'), ('b0', 'c1'),
 ('a0', 'b0'), ('a0', 'c2'), ('b0', 'c2'), ('a0', 'b1'), ('a0', 'c0'), ('b1', 'c0'), 
 ('a0', 'b1'), ('a0', 'c1'), ('b1', 'c1'), ('a0', 'b1'), ('a0', 'c2'), ('b1', 'c2'), 
 ('a1', 'b0'), ('a1', 'c0'), ('b0', 'c0'), ('a1', 'b0'), ('a1', 'c1'), ('b0', 'c1'), 
 ('a1', 'b0'), ('a1', 'c2'), ('b0', 'c2'), ('a1', 'b1'), ('a1', 'c0'), ('b1', 'c0'), 
 ('a1', 'b1'), ('a1', 'c1'), ('b1', 'c1'), ('a1', 'b1'), ('a1', 'c2'), ('b1', 'c2')]

However, this will have duplicates because of ('a0', 'b0', 'c0'), ('a0', 'b0', 'c1') and ('a0', 'b0', 'c2') all generate ('a0', 'b0'), so if you want to remove then you can just use a set, but you lose order:

In []:
{t for x in it.product(*s) for t in it.combinations(x, r=2)}

Out[]:
{('a1', 'c0'), ('b0', 'c1'), ('b0', 'c2'), ('a0', 'c1'), ('a0', 'c2'), ('b1', 'c1'), 
 ('b1', 'c2'), ('a1', 'b1'), ('a1', 'c1'), ('a1', 'c2'), ('b0', 'c0'), ('a0', 'c0'), 
 ('a1', 'b0'), ('b1', 'c0'), ('a0', 'b1'), ('a0', 'b0')}

Sorting it does put it back in order:

In []:
sorted({t for x in it.product(*s) for t in it.combinations(x, r=2)})

Out[]:
[('a0', 'b0'), ('a0', 'b1'), ('a0', 'c0'), ('a0', 'c1'), ('a0', 'c2'), ('a1', 'b0'), 
 ('a1', 'b1'), ('a1', 'c0'), ('a1', 'c1'), ('a1', 'c2'), ('b0', 'c0'), ('b0', 'c1'), 
 ('b0', 'c2'), ('b1', 'c0'), ('b1', 'c1'), ('b1', 'c2')]
AChampion
  • 29,683
  • 4
  • 59
  • 75
1

You can flatten your list, and create a simple recursive function (for results without repetition in the sublists):

d = [['a0', 'a1'], ['b0', 'b1'], ['c0', 'c1', 'c2']]
def combinations(d, current = []):
  if len(current) == 2:
    yield current
  else:
    for i in d:
      if i not in current:
        yield from combinations(d, current+[i])

print(list(combinations([i for b in d for i in b]))

Output:

[['a0', 'a1'], ['a0', 'b0'], ['a0', 'b1'], ['a0', 'c0'], ['a0', 'c1'], ['a0', 'c2'], ['a1', 'a0'], ['a1', 'b0'], ['a1', 'b1'], ['a1', 'c0'], ['a1', 'c1'], ['a1', 'c2'], ['b0', 'a0'], ['b0', 'a1'], ['b0', 'b1'], ['b0', 'c0'], ['b0', 'c1'], ['b0', 'c2'], ['b1', 'a0'], ['b1', 'a1'], ['b1', 'b0'], ['b1', 'c0'], ['b1', 'c1'], ['b1', 'c2'], ['c0', 'a0'], ['c0', 'a1'], ['c0', 'b0'], ['c0', 'b1'], ['c0', 'c1'], ['c0', 'c2'], ['c1', 'a0'], ['c1', 'a1'], ['c1', 'b0'], ['c1', 'b1'], ['c1', 'c0'], ['c1', 'c2'], ['c2', 'a0'], ['c2', 'a1'], ['c2', 'b0'], ['c2', 'b1'], ['c2', 'c0'], ['c2', 'c1']]
Ajax1234
  • 69,937
  • 8
  • 61
  • 102