45

I want something like the code below, but in a "Pythonic" style or using the standard library:

def combinations(a,b):
    for i in a:
        for j in b:
             yield(i,j)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dima
  • 2,012
  • 2
  • 17
  • 23
  • Could you provide some sample input and output? Currently you are creating a pair for each element in `a` and `b`. Is this really what you want? – Felix Kling Jun 27 '11 at 21:50

7 Answers7

54

These are not really "combinations" in the sense of combinatorics. These are rather elements from the Cartesian product of a and b. The function in the standard library to generate these pairs is itertools.product():

for i, j in itertools.product(a, b):
    # Whatever
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
50

As Sven said, your code is attempting to get all ordered pairs of elements of the lists a and b. In this case itertools.product(a,b) is what you want.

If instead you actually want "combinations", which are all unordered pairs of distinct elements of the list a, then you want itertools.combinations(a,2).

>>> for pair in itertools.combinations([1,2,3,4],2):
...    print pair
...
(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rob
  • 587
  • 5
  • 7
8

A nested generator expression will work too:

product = ((i, j) for i in a for j in b)
for i, j in product:
    # ...
mhyfritz
  • 8,342
  • 2
  • 29
  • 29
7

The itertools library has combinatorics functions. Like Sven stated, itertools.product would be the appropriate function in this case:

list(itertools.product('ab', 'cd'))
[('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd')]
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Håvard
  • 9,900
  • 1
  • 41
  • 46
5
>>>a=[1,2,3]
>>>b=[4,5,6]
>>>zip(a,b)
[(1, 4), (2, 5), (3, 6)] 
fransua
  • 1,559
  • 13
  • 30
  • 1
    I also want (1,5), (1,6), (2,4), (2,6), (3,4), (3,5) in addition to three pairs created by zip.... – Dima Jun 28 '11 at 04:00
  • 2
    Well, although @fransua got a -2 downvote, this is exactly what I needed as a pair. I will upvote your answer. – Shailen Sep 15 '14 at 15:04
3

A question we might ask is whether you want to generate all ordered pairs or all unordered pairs. The nested generator expression provided in the answer by mhyfritz will give you all ordered pairs.

If you want all unordered pairs (that is, (1, 2) and (2, 1) counts as the same pair), then you need to filter out the duplicates. An easy way to do this is to add a conditional to the end of the generator expression like so:

myList= [1, 2, 3, 4, 5]
unorderedPairGenerator = ((x, y) for x in myList for y in myList if y > x)
for pair in unorderedPairGenerator:
    print(pair)
#(1, 2)
#(1, 3)
#(1, 4)
#(1, 5)
#(2, 3)
#(2, 4)
#(2, 5)
#(3, 4)
#(3, 5)
#(4, 5)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mark_io
  • 81
  • 1
  • 4
2

Create set of pairs (even,odd) combination

>>> a = { (i,j) for i in range(0,10,2) for j in range(1,10,2)}  
>>> a
{(4, 7), (6, 9), (0, 7), (2, 1), (8, 9), (0, 3), (2, 5), (8, 5), (4, 9), (6, 7), (2, 9), (8, 1), (6, 3), (4, 1), (4, 5), (0, 5), (2, 3), (8, 7), (6, 5), (0, 1), (2, 7), (8, 3), (6, 1), (4, 3), (0, 9)}

def combinations(lista, listb):
    return { (i,j) for i in lista for j in listb }

>>> combinations([1,3,5,6],[11,21,133,134,443])
{(1, 21), (5, 133), (5, 11), (5, 134), (6, 11), (6, 134), (1, 443), (3, 11), (6, 21), (3, 21), (1, 133), (1, 134), (5, 21), (3, 134), (5, 443), (6, 443), (1, 11), (3, 443), (6, 133), (3, 133)}
wwright
  • 364
  • 2
  • 8