Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enumerating a tuple of indices with itertools.product

I am simultaneously iterating over multiple lists and want my generator to yield both the element and its index. If I had two lists, I would use a nested for loop:

for i_idx, i_val in enumerate(list_0):
    for j_idx, j_val in enumerate(list_1):
        print(i_idx, i_val, j_idx, j_val)

However, since I have more than two lists, the nested solution quickly becomes illegible. I would normally use itertools.product to neatly get the Cartesian product of my lists, but this strategy does not allow me to get the individual indices of elements in each list.

Here is what I have tried so far:

>>> from itertools import product

>>> list_0 = [1,2]
>>> list_1 = [3,4]
>>> list_2 = [5,6]

>>> for idx, pair in enumerate(product(list_0, list_1, list_2)):
...    print(idx, pair)
0 (1, 3, 5)
1 (1, 3, 6)
2 (1, 4, 5)
3 (1, 4, 6)
4 (2, 3, 5)
5 (2, 3, 6)
6 (2, 4, 5)
7 (2, 4, 6)

The output that I want is this:

0 0 0 (1, 3, 5)
0 0 1 (1, 3, 6)
0 1 0 (1, 4, 5)
0 1 1 (1, 4, 6)
1 0 0 (2, 3, 5)
1 0 1 (2, 3, 6)
1 1 0 (2, 4, 5)
1 1 1 (2, 4, 6)

where the first, second, and third columns are the indices of elements from the respective list. Is there clean way of doing this that is still legible when there are a large number of lists?

like image 936
Vivek Avatar asked Jun 03 '19 15:06

Vivek


People also ask

What does Product () do in Python?

product() is used to find the cartesian product from the given iterator, output is lexicographic ordered. The itertools. product() can used in two different ways: itertools.

What does product in Itertools do?

The product() method of the itertools module returns the cartesian product of the input iterables. The method takes an optional argument called repeat , which when used returns the cartesian product of the iterable with itself for the number of times specified in the repeat parameter.

Is Itertools faster than for loops?

That being said, the iterators from itertools are often significantly faster than regular iteration from a standard Python for loop.

What does the cycle function from Itertools module do?

There's an easy way to generate this sequence with the itertools. cycle() function. This function takes an iterable inputs as an argument and returns an infinite iterator over the values in inputs that returns to the beginning once the end of inputs is reached.


1 Answers

You can use zip and product again, in a function:

def enumerated_product(*args):
    yield from zip(product(*(range(len(x)) for x in args)), product(*args))

For example:

>>> for idx, pair in enumerated_product(list_0, list_1, list_2):
...     print(idx, pair)
...
(0, 0, 0) (1, 3, 5)
(0, 0, 1) (1, 3, 6)
(0, 1, 0) (1, 4, 5)
(0, 1, 1) (1, 4, 6)
(1, 0, 0) (2, 3, 5)
(1, 0, 1) (2, 3, 6)
(1, 1, 0) (2, 4, 5)
(1, 1, 1) (2, 4, 6)

For python2:

def enumerated_product(*args):
    for e in zip(product(*(range(len(x)) for x in args)), product(*args)):
        yield e
like image 73
Netwave Avatar answered Sep 23 '22 15:09

Netwave