1

Say I have a list, and I want to produce a list of all unique pairs of elements without considering the order. One way to do this is:

mylist = ['W','X','Y','Z']
for i in xrange(len(mylist)):
    for j in xrange(i+1,len(mylist)):
        print mylist[i],mylist[j]
W X
W Y
W Z
X Y
X Z
Y Z

I want to do this with iterators, I thought of the following, even though it doesn't have brevity:

import copy
it1 = iter(mylist)
for a in it1:
    it2 = copy.copy(it1)
    for b in it2:
        print a,b

But this doesn't even work. What is a more pythonic and efficient way of doing this, with iterators or zip, etc.?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
highBandWidth
  • 16,751
  • 20
  • 84
  • 131
  • It is the second time I've seen this homework question today. – Apalala Mar 11 '11 at 01:54
  • @Apalala, thanks for the downvote, but I actually wanted the answer for something I am coding and I couldn't find any other similar question while searching. – highBandWidth Mar 11 '11 at 02:04

2 Answers2

8

This has already been done and is included in the standard library as of Python 2.6:

import itertools

mylist = ['W', 'X', 'Y', 'Z']
for pair in itertools.combinations(mylist, 2):
    print pair        # pair is a tuple of 2 elements

Seems pretty Pythonic to me ;-)

Note that even if you're calculating a lot of combinations, the combinations() function returns an iterator so that you can start printing them right away. See the docs.

Also, you are referring to the result as a Cartesian product between the list and itself, but this is not strictly correct: The Cartesian product would have 16 elements (4x4). Your output is a subset of that, namely only the 2-element combinations (with repetition not allowed) of the values of the list.

Cameron
  • 96,106
  • 25
  • 196
  • 225
0

@Cameron's answer is correct.

I just wanted to point out that

for i in range(len(mylist)):
    do_something_to(mylist[i])

is nastily un-Pythonic; if your operation is read-only (does not have to be stored back to the array), do

for i in mylist:
    do_something_to(i)

otherwise

mylist = [do_something_to(i) for i in mylist]
Hugh Bothwell
  • 55,315
  • 8
  • 84
  • 99