tags:

views:

337

answers:

2

Hello everyone,

Using Python, I'd like to compare every possible pair in a list.

Suppose I have

my_list = [1,2,3,4]

I'd like to do an operation (let's call it foo) on every combination of 2 elements from the list.

The final result should be the same as

foo(1,1)
foo(1,2)
...
foo(4,3)
foo(4,4)

My first thought was to iterate twice through the list manually, but that doesn't seem very pythonic.

+10  A: 

Check out product() in the itertools module. It does exactly what you describe.

import itertools

my_list = [1,2,3,4]
for pair in itertools.product(my_list, repeat=2):
    foo(*pair)

This is equivalent to:

my_list = [1,2,3,4]
for x in my_list:
    for y in my_list:
        foo(x, y)

Edit: There are two very similar functions as well, permutations() and combinations(). To illustrate how they differ:

product() generates every possible pairing of elements, including all duplicates:

1,1  1,2  1,3  1,4
2,1  2,2  2,3  2,4
3,1  3,2  3,3  3,4
4,1  4,2  4,3  4,4

permutations() generates all unique orderings of each unique pair of elements, eliminating the x,x duplicates:

 .   1,2  1,3  1,4
2,1   .   2,3  2,4
3,1  3,2   .   3,4
4,1  4,2  4,3   .

Finally, combinations() only generates each unique pair of elements, in lexicographic order:

 .   1,2  1,3  1,4
 .    .   2,3  2,4
 .    .    .   3,4
 .    .    .    .

All three of these functions were introduced in Python 2.6.

Ben Blank
Didn't know about itertools, this is perfect. Thanks !
GuiSim
Odd, when I run itertools.product(my_list, 2), it complains that int isn't callable. Works once I change it to: itertools.product(my_list, repeat=2)
ojrac
(using Python 2.6.2)
ojrac
Note that itertools.product() is new in Python 2.6.
Mike Mazur
Actually what I was looking for is itertools.combinations .. but I was not clear in my question. I still got my answer thanks to you ;)
GuiSim
+1. itertools is awesome, and gained a bunch of new functions in Python 2.6. Every newbie python tutorial should introduce this module IMHO.
nakedfanatic
Just for posterity, I'll point out that itertools.combinations would not generate the foo(1,1) or foo(4,4) lines in the original example.
Kylotan
@GuiSim — I wondered if that might be the case. In fact, for a few seconds after first posting it, my answer actually had combinations() instead of product() until I realized you had the (1, 1) and (4, 4) points listed. :-)
Ben Blank
@orajc — Right you are! It's a named-only parameter because `product()` can take any number of iterables as arguments. I with I'd caught that sooner. :-)
Ben Blank
A: 

If you're just calling a function, you can't really do much better than:

for i in my_list:
    for j in my_list:
        foo(i, j)

If you want to collect a list of the results of calling the function, you can do:

[foo(i, j) for i my_list for j in my_list]

which will return you a list of the result of applying foo(i, j) to each possible pair (i, j).

Adam Rosenfield