Search code examples
pythonsetpython-2.xproductpython-itertools

Product of multiple lists--individual lists vs array of lists, need help understanding


Forewarning: I'm new to Python and I'm teaching myself, so this question may just have a trivial solution--any help (and patience) is very much appreciated!

Okay, big picture is that I want to get the union of all possible intersections of a variable number of lists. I'm not really sure how to explain the general-case problem I'm running into, so for the sake of this question, I'll just use an example with 3 lists (but again, the actual number of lists will vary):

Suppose we have the following:

>>>from itertools import product

>>>l1=[1,2,3]
>>>l2=[1,4,5]
>>>l3=[1,6,7]
>>>
>>>array=[l1,l2,l3]
>>>
>>>
>>>list(product(array))
[([1, 2, 3],), ([1, 4, 5],), ([1, 6, 7],)]
>>>
>>>list(product(l1,l2,l3)
[(1, 1, 1), (1, 1, 6), (1, 1, 7), (1, 4, 1), (1, 4, 6), (1, 4, 7), (1, 5, 1), (1, 5, 6), (1, 5, 7), (2, 1, 1), (2, 1, 6), (2, 1, 7), (2, 4, 1), (2, 4, 6), (2, 4, 7), (2, 5, 1), (2, 5, 6), (2, 5, 7), (3, 1, 1), (3, 1, 6), (3, 1, 7), (3, 4, 1), (3, 4, 6), (3, 4, 7), (3, 5, 1), (3, 5, 6), (3, 5, 7)]

My questions are:

  1. Why doesn't list(product(array)) == list(product(l1,l2,l3))?
  2. Using array, how can I get the same output as list(product(l1,l2,l3))?

For more context:

Ultimately, the goal is to get the union of all possible combinations of the intersections of the lists. I.e.;

1>>>for x in product(l1,l2,l3):
...     newArray.append(reduce(set.intersection, [set(e) for e in array])
2>>>u=reduce(set.union, [set(e) for e in newArray])
3>>>u
set([1])

Except, because I don't know how many lists I'll have (in my code, they're being appended onto array by a loop), I want line 1 to be something like for x in product(array):, not for x in product(l1,l2,l3):.


Solution

  • 1) Why doesn't list(product(array))=list(product(l1,l2,l3))?

    Well the itertools.product() takes in iterables and then produces the Cartesian product amongst them. So when you do list(product(array)) you are basically trying to take cartesian product of a single list(?) and notice the commas in the output of the same signifying cartesian product between one list and empty iterable.

    2) Using array, how can I get the same output as list(product(l1,l2,l3))?

    Notice your problem boils down to being to convert the arr list to *args while calling the function.We have the * operator for this, So for the answer just do:

    product(*arr)

    From the python documentation:

    If the syntax *expression appears in the function call, expression must evaluate to an iterable. Elements from this iterable are treated as if they were additional positional arguments; if there are positional arguments x1, ..., xN, and expression evaluates to a sequence y1, ..., yM, this is equivalent to a call with M+N positional arguments x1, ..., xN, y1, ..., yM.

    Since you must mentioned that you are learning on your own, this is also covered in the python tutorial, in a section titled Unpacking argument lists.