在 itertools.products 中命名可迭代的部分
Posted
技术标签:
【中文标题】在 itertools.products 中命名可迭代的部分【英文标题】:Name parts of iterables in itertools.products 【发布时间】:2012-02-01 15:09:07 【问题描述】:我一直在阅读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
【问题讨论】:
从文档中我会说它总是按参数的顺序出现。 菲利克斯,完全正确。 【参考方案1】:itertools.product([1, 2, 3], [1, 2])
的输出是一系列有序对,第一个元素来自[1,2,3]
,第二个元素来自[1,2]
。这是有保证的行为。
如果需要字段名称,您可以将结果转换为 named 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)
【讨论】:
【参考方案2】:结果将始终根据产品的参数顺序进行排序,即在(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))
【讨论】:
返回命名元组比返回字典更好。后者创建成本更高,占用更多内存,并且失去了笛卡尔积的顺序。话虽如此,对于**items
的创造性使用 +1。以上是关于在 itertools.products 中命名可迭代的部分的主要内容,如果未能解决你的问题,请参考以下文章
在 libc++ 的内联命名空间中前向声明类的可移植方式是啥?