[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

Creating unique combinations from lists

breal

1/16/2008 7:15:00 PM

I have three lists... for instance

a = ['big', 'small', 'medium'];
b = ['old', 'new'];
c = ['blue', 'green'];

I want to take those and end up with all of the combinations they
create like the following lists
['big', 'old', 'blue']
['small', 'old', 'blue']
['medium', 'old', 'blue']
['big', 'old', 'green']
['small', 'old', 'green']
['medium', 'small', 'green']
['big', 'new', 'blue']
['small', 'new', 'blue']
['medium', 'new', 'blue']
['big', 'new', 'green']
['small', 'new', 'green']
['medium', 'new', 'green' ]

I could do nested for ... in loops, but was looking for a Pythonic way
to do this. Ideas?
14 Answers

Reedick, Andrew

1/16/2008 7:33:00 PM

0



> -----Original Message-----
> From: python-list-bounces+jr9445=att.com@python.org [mailto:python-
> list-bounces+jr9445=att.com@python.org] On Behalf Of breal
> Sent: Wednesday, January 16, 2008 2:15 PM
> To: python-list@python.org
> Subject: Creating unique combinations from lists
>
> I have three lists... for instance
>
> a = ['big', 'small', 'medium'];
> b = ['old', 'new'];
> c = ['blue', 'green'];
>
> I want to take those and end up with all of the combinations they
> create like the following lists
> ['big', 'old', 'blue']
> ['small', 'old', 'blue']
> ['medium', 'old', 'blue']
> ['big', 'old', 'green']
> ['small', 'old', 'green']
> ['medium', 'small', 'green']
> ['big', 'new', 'blue']
> ['small', 'new', 'blue']
> ['medium', 'new', 'blue']
> ['big', 'new', 'green']
> ['small', 'new', 'green']
> ['medium', 'new', 'green' ]
>
> I could do nested for ... in loops, but was looking for a Pythonic way
> to do this. Ideas?


http://www.python.org/dev/peps...

breal

1/16/2008 7:44:00 PM

0

On Jan 16, 11:33 am, "Reedick, Andrew" <jr9...@ATT.COM> wrote:
> > -----Original Message-----
> > From: python-list-bounces+jr9445=att....@python.org [mailto:python-
> > list-bounces+jr9445=att....@python.org] On Behalf Of breal
> > Sent: Wednesday, January 16, 2008 2:15 PM
> > To: python-l...@python.org
> > Subject: Creating unique combinations from lists
>
> > I have three lists... for instance
>
> > a = ['big', 'small', 'medium'];
> > b = ['old', 'new'];
> > c = ['blue', 'green'];
>
> > I want to take those and end up with all of the combinations they
> > create like the following lists
> > ['big', 'old', 'blue']
> > ['small', 'old', 'blue']
> > ['medium', 'old', 'blue']
> > ['big', 'old', 'green']
> > ['small', 'old', 'green']
> > ['medium', 'small', 'green']
> > ['big', 'new', 'blue']
> > ['small', 'new', 'blue']
> > ['medium', 'new', 'blue']
> > ['big', 'new', 'green']
> > ['small', 'new', 'green']
> > ['medium', 'new', 'green' ]
>
> > I could do nested for ... in loops, but was looking for a Pythonic way
> > to do this. Ideas?
>
> http://www.python.org/dev/peps...

Thanks for the reply. I never realized you could use list
comprehension like this... AWESOME!

Martin v. Loewis

1/16/2008 7:54:00 PM

0

> I could do nested for ... in loops, but was looking for a Pythonic way
> to do this. Ideas?

I find nested for loops very Pythonic. Explicit is better than implicit,
and simple is better than complex.

Regards,
Martin

Tim Chase

1/16/2008 8:40:00 PM

0

> a = ['big', 'small', 'medium'];
> b = ['old', 'new'];
> c = ['blue', 'green'];
>
> I want to take those and end up with all of the combinations they
> create like the following lists
> ['big', 'old', 'blue']
> ['small', 'old', 'blue']
> ['medium', 'old', 'blue']
> ['big', 'old', 'green']
> ['small', 'old', 'green']
> ['medium', 'small', 'green']
> ['big', 'new', 'blue']
> ['small', 'new', 'blue']
> ['medium', 'new', 'blue']
> ['big', 'new', 'green']
> ['small', 'new', 'green']
> ['medium', 'new', 'green' ]
>
> I could do nested for ... in loops, but was looking for a Pythonic way
> to do this. Ideas?

You can use a recursive generator:

def iterall(*iterables):
if iterables:
for head in iterables[0]:
for remainder in iterall(*iterables[1:]):
yield [head] + remainder
else:
yield []

for thing in iterall(
['big', 'medium', 'small'],
['old', 'new'],
['blue', 'green'],
):
print thing

The two for-loops plus recursion should handle any number of
parameters, so if you were so inclined, you could do

for thing in iterall(
['big', 'medium', 'small'],
['old', 'new'],
['blue', 'green'],
['smelly', 'fragrant'],
['spatula', 'avocado'],
):
print thing

and get all 3*2*2*2*2 items. Or count in binary:

for i, bitstream in enumerate(iterall(
[0, 1],
[0, 1],
[0, 1],
[0, 1],
[0, 1],
[0, 1],
)):
print ''.join(map(str, bitstream)), '=', i

When you're iterating over combinations of items in groups of
lists, I prefer the clarity of this over something like

[(a,b,c,d,e) for a in [0,1] for b in [0,1] for c in [0,1] for
d in [0,1] for e in [0,1]]


-tkc


Matt McCredie

1/16/2008 9:25:00 PM

0

On Jan 16, 11:15 am, breal <hacker.steven...@gmail.com> wrote:
> I have three lists... for instance
>
> a = ['big', 'small', 'medium'];
> b = ['old', 'new'];
> c = ['blue', 'green'];
>
> I want to take those and end up with all of the combinations they
> create like the following lists
> ['big', 'old', 'blue']
> ['small', 'old', 'blue']
> ['medium', 'old', 'blue']
> ['big', 'old', 'green']
> ['small', 'old', 'green']
> ['medium', 'small', 'green']
> ['big', 'new', 'blue']
> ['small', 'new', 'blue']
> ['medium', 'new', 'blue']
> ['big', 'new', 'green']
> ['small', 'new', 'green']
> ['medium', 'new', 'green' ]
>
> I could do nested for ... in loops, but was looking for a Pythonic way
> to do this. Ideas?

I would probably just create a generator:

def permute(a,b,c):
for x in a:
for y in b:
for z in c:
yield [x,y,z]

all_combos = list(permute(
['big', 'small', 'medium'],
['old', 'new'],
['blue', 'green']))

print all_combos


I'm using nested for loops, but I sure find it easy to read that way.
Though, using list comprehension does pretty much the same thing. It
appears that Tim Chase has posted a more generic version of the above.

Matt

Steven D'Aprano

1/16/2008 10:01:00 PM

0

On Wed, 16 Jan 2008 11:15:16 -0800, breal wrote:

> I could do nested for ... in loops, but was looking for a Pythonic way
> to do this. Ideas?

What makes you think nested loops aren't Pythonic?


--
Steven

Tim Chase

1/16/2008 10:23:00 PM

0

>> I could do nested for ... in loops, but was looking for a Pythonic way
>> to do this. Ideas?
>
> What makes you think nested loops aren't Pythonic?

On their own, nested loops aren't a bad thing. I suspect they
become un-Pythonic when they make code look ugly and show a
broken model of the problem. There's a big diffence between:

# iterate over a 10x10 grid
for i in xrange(10):
for j in xrange(10):
print i,j

which is pretty manageable, but quickly becomes very unpythonic
if the problem is poorly defined:

for a in range(5):
for b in range(5):
for c in range(5):
for d in range(5):
for e in range(5):
for f in range(5):
for g in range(5):
for h in range(5):
for i in range(5):
for j in range(5):
for k in range(5):
for l in range(5):
for m in range(5):
for n in range(5):
for o in range(5):
for p in range(5):
for q in range(5):
for r in range(5):
for s in range(5):
for t in range(5):
for u in range(5):
for v in range(5):
for w in range(5):
for x in range(5):
for y in range(5):
for z in range(5):
print a,b,c,d,e,f,g,
print h,i,j,k,l,m,n,
print o,p,q,r,s,t,u,
print v,w,x,y,z

It gets even worse if your loop nesting is based on something
external. You wouldn't want code that looks like

if len(input) == 2:
for a in range(5):
for b in range(5):
whatever(a,b)
elif len(input) == 3:
for a in range(5):
for b in range(5):
for c in range(5):
whatever(a,b,c)
elif len(input) == 4:
...

Contributing to the unpythonic'ness (unpythonicity?) of it is
that something is clearly happening at a higher level than just
for-loops so other Python constructs should be used to express
them instead of abusing your code to do your dirty work.

-tkc






Neil McCallum

1/16/2008 10:41:00 PM

0


>
> for a in range(5):
....
> for z in range(5):

means the inner loop runs 5**26 times so perhaps it's not only
unpythonic but also uncomputable...

Tim Chase

1/16/2008 10:52:00 PM

0

>> for a in range(5):
> ...
>> for z in range(5):
>
> means the inner loop runs 5**26 times so perhaps it's not only
> unpythonic but also uncomputable...

only if you're impatient ;)

yes, it was a contrived pessimal example. It could be range(2)
to generate boolean-number sequences. I've done 2**26 loops in
code before (well, it was on the way to 2**32, just to see how
long it took to roll over and hit an error condition).

The main emphasis was to show that there was a pattern unfolding
that should have been translated into more pythonic code than
just hard-coding nested loops.

-tkc



Martin v. Loewis

1/17/2008 5:21:00 AM

0

> The main emphasis was to show that there was a pattern unfolding that
> should have been translated into more pythonic code than just
> hard-coding nested loops.

Practicality beats purity. That you would solve a more general problem
in a more general way doesn't mean that you shouldn't solve the more
specific problem (combinations from three sets) in a specific,
easy-to-read way. Readability counts.

I find your solution (with nested generators) *very* unpythonic. It
is much more complicated than necessary to solve the problem at hand,
and it doesn't get Pythonic just by using the latest language features.
It may be a smart solution, but not a Pythonic one.

Regards,
Martin

P.S. To solve the general problem, I like

http://aspn.activestate.com/ASPN/Cookbook/Python/Rec...