views:

183

answers:

3

The following appears in my Python 2.6 code:

for src, dst in ([s,d] for s in universe for d in universe if s != d):

Can I do much better? What I particularly don't like is that I'm in effect specifying the same pair twice, once for the for loop and again for the generator expression. I'm uncertain whether I'd prefer:

for src, dst in itertools.product(universe, universe):
    if src != dst:

Is there a way to express this loop concisely?

universe happens to be a list, if it makes any difference. Order of iteration doesn't matter.

+3  A: 

You could use simple nested for-loops:

for src in universe:
   for dst in universe:
      if src == dst:
         continue
      ...

I'd say this is the most easy to read syntax in this case.

sth
You may well be right. I hate it when the purely imperative code is the simplest ;-)
Steve Jessop
Accepting this answer, which I read as, "no, you can't do *much* better"...
Steve Jessop
+1  A: 

itertools.product can take a "repeat" keyword argument if you want to have the same sequence as more than one parameter:

itertools.product(universe, repeat=2)

it is a matter of opinion as to whether this is more readable.

You could replace your original code with:

for (src, dest) in filter(lambda (a,b): a!=b, itertools.product(universe, repeat=2)):
    ...
Dave Kirby
Nice. I didn't know you could do that.
Jason R. Coombs
+2  A: 

I suggest keeping it entirely functional or entirely with comprehensions. Here's an implementation that's entirely functional.

import itertools 
import operator

def inner_product(iterable):
    "the product of an iterable with itself"
    return itertools.product(iterable, repeat=2)

def same(pair):
    "does this pair contain two of the same thing?"
    return operator.is_(*pair)

universe = 'abcd'

pairs = inner_product(universe)
unique_pairs = itertools.ifilterfalse(same, pairs)
for pair in unique_pairs:
    print pair

"""
('a', 'b')
('a', 'c')
('a', 'd')
('b', 'a')
('b', 'c')
('b', 'd')
('c', 'a')
('c', 'b')
('c', 'd')
('d', 'a')
('d', 'b')
('d', 'c')
"""
Jason R. Coombs
I like this in principle. In practice, the code might be maintained by people who don't/barely know Python, so I don't think I dare actually use it this time.
Steve Jessop