By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,730 Members | 1,659 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,730 IT Pros & Developers. It's quick & easy.

Creating unique combinations from lists

P: n/a
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?
Jan 16 '08 #1
Share this Question
Share on Google+
11 Replies


P: n/a

-----Original Message-----
From: py********************************@python.org [mailto:python-
li*************************@python.org] On Behalf Of breal
Sent: Wednesday, January 16, 2008 2:15 PM
To: py*********@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/pep-0202/

Jan 16 '08 #2

P: n/a
On Jan 16, 11:33 am, "Reedick, Andrew" <jr9...@ATT.COMwrote:
-----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/pep-0202/
Thanks for the reply. I never realized you could use list
comprehension like this... AWESOME!
Jan 16 '08 #3

P: n/a
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
Jan 16 '08 #4

P: n/a
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
Jan 16 '08 #5

P: n/a
On Jan 16, 11:15 am, breal <hacker.steven...@gmail.comwrote:
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
Jan 16 '08 #6

P: n/a
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
Jan 16 '08 #7

P: n/a
>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


Jan 16 '08 #8

P: n/a
>
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...
Jan 16 '08 #9

P: n/a
> 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

Jan 16 '08 #10

P: n/a
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/Coo.../Recipe/496807
Jan 17 '08 #11

P: n/a
On Thu, 17 Jan 2008 10:44:51 -0600, Reedick, Andrew wrote:
>-----Original Message-----
From: Tim Chase [mailto:py*********@tim.thechases.com] Sent: Thursday,
January 17, 2008 10:30 AM To: Reedick, Andrew
Cc: breal; py*********@python.org; ma****@v.loewis.de Subject: Re:
Creating unique combinations from lists

Yick...a nice demo of the power of eval, but definitely filed under the
"Hack" heading

You hurt my feeling. *sniffle* Given how late python
compiles/evaluates code blocks, I'm thinking that eval() is less hack
and more paradigm ..err.. pythonic. ;-)
I see your smiley, but even so, do you have any idea how many times eval
is used in the standard library? Not very often.

$ pwd
/usr/lib/python2.5
$ grep -r "eval(.*)" *.py | wc -l
20

Some of those twenty matches are false positives. I manually inspected
them, and by my count there are just ten actual uses of eval:

bdb.py: return eval(expr, globals, locals)
dumbdbm.py: key, pos_and_siz_pair = eval(line)
gettext.py: return eval('lambda n: int(%s)' % plural)
gopherlib.py: _type_to_name_map[eval(name)] = name[2:]
mhlib.py: def do(s): print s; print eval(s)
os.py: eval(name)
pdb.py: x = eval(arg, {}, {})
rexec.py: return eval(code, m.__dict__)
rlcompleter.py: object = eval(expr, self.namespace)
warnings.py: cat = eval(category)
I haven't made any effort to determine how many of them are gaping great
big security holes.

--
Steven
Jan 18 '08 #12

This discussion thread is closed

Replies have been disabled for this discussion.