Cartesian Product of two lists (itertools)

2009-01-25 Thread Thorsten Kampe
Hi,

is there a way to make itertools.product generate triples instead of 
pairs from two lists?

For example:
 list1 = [1, 2]; list2 = [4, 5]; list3 = [7, 8]
 from itertools import product
 list(product(list1, list2, list3))
[(1, 4, 7), (1, 4, 8), (1, 5, 7), (1, 5, 8), (2, 4, 7), (2, 4, 8), (2, 
5, 7), (2, 5, 8)]

so far so good... Now...
 list(product(product(list1, list2), list3))
[((1, 4), 7), ((1, 4), 8), ((1, 5), 7), ((1, 5), 8), ((2, 4), 7), ((2, 
4), 8), ((2, 5), 7), ((2, 5), 8)]

Oops, pairs of pairs instead triples. Not what I wanted.

What's the best way to pre-process the arguments to itertools.product 
or to post-process the result of itertools.product to get what I 
want?!

I have an older utility which I would like to replace with 
itertools.product. The old one uses a rather clumsy way to indicate that 
a triple was wanted:

def cartes(seq0, seq1, modus = 'pair'):
 return the Cartesian Product of two sequences 
if   modus == 'pair':
return [[item0, item1] for item0 in seq0 for item1 in seq1]
elif modus == 'triple':
return [item0 + [item1] for item0 in seq0 for item1 in seq1]


Thorsten
--
http://mail.python.org/mailman/listinfo/python-list


Re: Cartesian Product of two lists (itertools)

2009-01-25 Thread Mensanator
On Jan 25, 3:12�pm, Thorsten Kampe thors...@thorstenkampe.de wrote:
 Hi,

 is there a way to make itertools.product generate triples instead of
 pairs from two lists?

 For example: list1 = [1, 2]; list2 = [4, 5]; list3 = [7, 8]
  from itertools import product
  list(product(list1, list2, list3))

 [(1, 4, 7), (1, 4, 8), (1, 5, 7), (1, 5, 8), (2, 4, 7), (2, 4, 8), (2,
 5, 7), (2, 5, 8)]

 so far so good... Now... list(product(product(list1, list2), list3))

 [((1, 4), 7), ((1, 4), 8), ((1, 5), 7), ((1, 5), 8), ((2, 4), 7), ((2,
 4), 8), ((2, 5), 7), ((2, 5), 8)]

 Oops, pairs of pairs instead triples. Not what I wanted.

 What's the best way to pre-process the arguments to itertools.product
 or to post-process the result of itertools.product to get what I
 want?!

 I have an older utility which I would like to replace with
 itertools.product. The old one uses a rather clumsy way to indicate that
 a triple was wanted:

 def cartes(seq0, seq1, modus = 'pair'):
 � �  return the Cartesian Product of two sequences 
 � � if � modus == 'pair':
 � � � � return [[item0, item1] for item0 in seq0 for item1 in seq1]
 � � elif modus == 'triple':
 � � � � return [item0 + [item1] for item0 in seq0 for item1 in seq1]

 Thorsten

Will this work for you?

 list4 = [(i,) for i in list3]

 list4
[(7,), (8,)]

 a = list(itertools.product(itertools.product(list1, list2), list4))
 a
[((1, 4), (7,)), ((1, 4), (8,)), ((1, 5), (7,)), ((1, 5), (8,)), ((2,
4), (7,)), ((2, 4), (8,)), ((2, 5), (7,)), ((2, 5), (8,))]

 def flatten(listOfLists):
return tuple(itertools.chain.from_iterable(listOfLists))

 list5 = [flatten(i) for i in a]
 list5
[(1, 4, 7), (1, 4, 8), (1, 5, 7), (1, 5, 8), (2, 4, 7), (2, 4, 8), (2,
5, 7), (2, 5, 8)]

--
http://mail.python.org/mailman/listinfo/python-list


Re: Cartesian Product of two lists (itertools)

2009-01-25 Thread Terry Reedy

Thorsten Kampe wrote:

Hi,

is there a way to make itertools.product generate triples instead of 
pairs from two lists?


For example:

list1 = [1, 2]; list2 = [4, 5]; list3 = [7, 8]
from itertools import product
list(product(list1, list2, list3))
[(1, 4, 7), (1, 4, 8), (1, 5, 7), (1, 5, 8), (2, 4, 7), (2, 4, 8), (2, 
5, 7), (2, 5, 8)]


so far so good... Now...

list(product(product(list1, list2), list3))
[((1, 4), 7), ((1, 4), 8), ((1, 5), 7), ((1, 5), 8), ((2, 4), 7), ((2, 
4), 8), ((2, 5), 7), ((2, 5), 8)]


Oops, pairs of pairs instead triples. Not what I wanted.

What's the best way to pre-process the arguments to itertools.product 
or to post-process the result of itertools.product to get what I 
want?!


I have an older utility which I would like to replace with 
itertools.product. The old one uses a rather clumsy way to indicate that 
a triple was wanted:


A pair of function, cart_pair, cart_trip, would have been better.
Or auto recognition of the number of sequences passed in.


def cartes(seq0, seq1, modus = 'pair'):
 return the Cartesian Product of two sequences 
if   modus == 'pair':
return [[item0, item1] for item0 in seq0 for item1 in seq1]
elif modus == 'triple':
return [item0 + [item1] for item0 in seq0 for item1 in seq1]


The second branch only produces a triple if seq0 is a sequence of pairs. 
 This must be called with something like

  res = cartes(cartes(list1,list2),list3,'triple')
Just replace that with your first only-once itertools call
  list(product(list1, list2, list3))

--
http://mail.python.org/mailman/listinfo/python-list


Re: Cartesian Product of two lists (itertools)

2009-01-25 Thread Mark Wooding
Thorsten Kampe thors...@thorstenkampe.de writes:

 [((1, 4), 7), ((1, 4), 8), ((1, 5), 7), ((1, 5), 8), ((2, 4), 7), ((2, 
 4), 8), ((2, 5), 7), ((2, 5), 8)]

[...]

 What's the best way to pre-process the arguments to itertools.product 
 or to post-process the result of itertools.product to get what I 
 want?!

Python has powerful destructuring capabilities:

[(x, y, z) for ((x, y), z) in lopsided_list]

This seems simpler and is probably faster than a generalized flatten for
this size of problem, but I wouldn't use it to rearrange tuples with
more than four or five elements.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list