Назовите части итераций в itertools.products - PullRequest
6 голосов
/ 01 февраля 2012

Я читал о itertools, который кажется очень мощным модулем. Я особенно заинтересован в itertools.product(), который дает мне все комбинации повторяемых входных данных.

Тем не менее, я хотел бы знать, из каких итераций ввода поступает каждый из выходов. Например, простой стандартный пример:

itertools.product([1, 2, 3], [1, 2])

Если пользователь предоставил входные данные для [1,2,3], [1, 2], я не буду знать, в каком порядке они пришли, поэтому получаю результат

(1, 2)

не сильно помогает, так как я не знаю, в какую сторону они будут. Есть ли какой-нибудь способ предоставления ввода, например:

itertools.product(foo = [1, 2, 3], bar = [1, 2])

, а затем получить выходные данные, такие как:

output['foo'] = 1
output['bar'] = 2

или

output.foo = 1
output.bar = 2

Ответы [ 2 ]

17 голосов
/ 01 февраля 2012

Вывод itertools.product([1, 2, 3], [1, 2]) представляет собой последовательность упорядоченных пар, независимо от того, является ли первый элемент из [1,2,3], а второй - из [1,2]. Это гарантированное поведение.

Если требуются имена полей, вы можете преобразовать результат в с именем tuple . Как вы и просили, именованный кортеж позволяет вам получить доступ к полям с output.foo и output.bar. Включая идею KennyTM об использовании **items, он может быть упакован в единую функцию, которая быстро и эффективно использует память:

from itertools import product, starmap
from collections import namedtuple

def named_product(**items):
    Product = namedtuple('Product', items.keys())
    return starmap(Product, product(*items.values()))

Вот пример вызова:

>>> for output in named_product(foo=[1,2,3], bar=[1,2]):
        print output

Product(foo=1, bar=1)
Product(foo=1, bar=2)
Product(foo=2, bar=1)
Product(foo=2, bar=2)
Product(foo=3, bar=1)
Product(foo=3, bar=2)
5 голосов
/ 01 февраля 2012

Результат всегда будет упорядочен в соответствии с порядком аргументов продукта, т. Е. В (1, 2) значение 1 должно быть от [1,2,3], а значение 2 должно быть от [1,2].

Следовательно, ваше требование может быть удовлетворено путем повторного использования itertools.product:

def named_product(**items):
    names = items.keys()
    vals = items.values()
    for res in itertools.product(*vals):
        yield dict(zip(names, res))
...