在itertools.products中,命名可迭代对象的部分是什么?

10
我一直在研究似乎非常强大的模块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

8
根据文档,我认为参数总是以它们的顺序出现。 - Felix Kling
费利克斯,那完全正确。 - Raymond Hettinger
2个回答

23
itertools.product([1, 2, 3], [1, 2])的输出是一系列有序对,其中第一个元素来自[1,2,3],第二个元素来自[1,2]。这是保证的行为。如果需要字段名,可以将结果转换为named tuple(命名元组)。按照您的要求,通过命名元组可以使用output.foooutput.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

结果将始终按照产品的参数顺序排序,即在 (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))

最好返回一个namedtuple而不是字典。后者创建起来更昂贵,占用更多内存,并且会失去笛卡尔积的顺序。话虽如此,“**items” 的创造性使用值得赞赏。 - Raymond Hettinger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接