0

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):.

martineau
  • 119,623
  • 25
  • 170
  • 301
Emm Gee
  • 165
  • 7
  • 1
    You just want `product(*array)` here. Do you understand the “splat syntax”, pasting an iterable into a function call as a bunch of separate arguments, or do you need a link to an explanation? – abarnert Aug 04 '18 at 02:06
  • If you're curious why `product(array)` (and even `product()`) is legal despite being useless: First, mathematically, you can write `product_n=1_to_1(n)`. More importantly, it means you can write `product(*rows)` even when `rows` is some value you were passed by a caller that may only have one row, or none, and you can likewise write `product(array, repeat=power)` even if `power` might be only 1 or 0. – abarnert Aug 04 '18 at 02:20
  • @abarnert: Thank you, `product(*array)` worked! Also, a link to an explanation on 'splat syntax' will be helpful! – Emm Gee Aug 04 '18 at 19:14

1 Answers1

0

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.

Aviral Verma
  • 488
  • 4
  • 11