Как получить декартово произведение в Python с помощью генератора? - PullRequest
1 голос
/ 08 мая 2020

Я пытаюсь получить декартово произведение нескольких массивов, но массивы довольно большие, и я пытаюсь оптимизировать использование памяти. Я попытался реализовать генератор, используя приведенный ниже код, но он просто возвращает, что генератор находится в определенном месте.

import itertools

x = [[1,2],[3,4]]

def iter_tools(*array):
    yield list(itertools.product(*array))

print(iter_tools(*x))

Когда я пробую тот же код, но с return вместо yield, он работает нормально. Как я мог получить декартово произведение, реализовав генератор?

Ответы [ 3 ]

2 голосов
/ 08 мая 2020

Итог, itertools.product уже является итератором . Вам не нужно писать свои собственные. (Генератор - это своего рода итератор.) Например:

>>> x = [[1, 2], [3, 4]]
>>> p = itertools.product(*x)
>>> next(p)
(1, 3)
>>> next(p)
(1, 4)

Теперь, чтобы объяснить, кажется, что вы неправильно понимаете что-то фундаментальное. Функция генератора возвращает итератор генератора . Вот что вы видите из print:

>>> iter_tools(*x)
<generator object iter_tools at 0x7f05d9bc3660>

Используйте list() для приведения итератора к списку.

>>> list(iter_tools(*x))
[[(1, 3), (1, 4), (2, 3), (2, 4)]]

Обратите внимание, что это вложенный список. Это потому, что ваш iter_tools дает один список, а не больше ничего. В этой заметке эта часть не имеет смысла, потому что приведение itertools.product к списку сводит на нет всю цель итератора - ленивое вычисление . Если вы действительно хотите получить значения от итератора, вы должны использовать yield from:

def iter_tools(*array):
    yield from itertools.product(*array)

В этом случае iter_tools бессмысленно, но если ваш фактический iter_tools более сложный, это может

См. также:


Этот ответ частично основан на juanpa.arrivillaga s комментарий

0 голосов
/ 08 мая 2020

Идея генератора заключается в том, что вы не делаете все вычисления одновременно, как при вызове list(itertools.product(*array)). Итак, что вы хотите сделать, это сгенерировать результатов один за другим. Например, вот так:

def iter_tools(*array):
    for i in array[0]:
        for j in array[1]:
            yield (i, j)

Затем вы можете сделать что-нибудь с каждым результирующим кортежем следующим образом:

for tup in iter_tools(*x):
    print(tup)

Конечно, вы можете легко адаптировать генератор так, чтобы он выдавал каждую строку или столбцов за звонок.

Или, если вас устраивает то, что предлагает itertools:

for i in itertools.product(*x):
    print(i)

Что вам нужно, зависит от вашего варианта использования. Надеюсь, я смогу вам помочь :)

0 голосов
/ 08 мая 2020

Если вы хотите получить отдельный элемент из декартова произведения, вам нужно перебрать произведение:

import itertools

x = [[1,2],[3,4]]

def iter_tools(*array):
    for a in itertools.product(*array):
        yield a

for a in iter_tools(*x):
    print(a)

...