在 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.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)

【讨论】:

【参考方案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++ 的内联命名空间中前向声明类的可移植方式是啥?

如何在Makefile中命名我自己的可执行文件?

Jinja2:如何在包含的模板和可扩展模板中使用命名块

Python 和 asyncio:封闭的命名管道始终可供读取

为啥命名管道是本地的?

来自不同命名空间的同名对象的可重用函数代码?