首页 > 解决方案 > 如何创建一个迭代列表,其中一些变量是独立的,一些是依赖的?

问题描述

我正在尝试列出排列顺序,其中前两个变量和后两个变量之间的顺序很重要,但在这两组之间不重要。我已经能够得到这样的东西:

>>>[p for p in itertools.product([1, 2],[1, 2],[5, 6], [5, 6])]

   [(1, 1, 5, 5), (1, 1, 5, 6), (1, 1, 6, 5), (1, 1, 6, 6), (1, 2, 5, 5),
    (1, 2, 5, 6), (1, 2, 6, 5), (1, 2, 6, 6), (2, 1, 5, 5), (2, 1, 5, 6), 
    (2, 1, 6, 5), (2, 1, 6, 6), (2, 2, 5, 5), (2, 2, 5, 6), (2, 2, 6, 5), 
    (2, 2, 6, 6)]

我想得到一些没有切换顺序重复但保留重复变量的东西,如下所示:

   [(1, 1, 5, 5), (1, 1, 5, 6), (1, 1, 6, 6), (1, 2, 5, 5),(1, 2, 5, 6), 
    (1, 2, 6, 6), (2, 2, 5, 5), (2, 2, 5, 6), (2, 2, 6, 6)]

似乎应该有一种直接的方法来做到这一点,我只是还没有想出它(我主要在 R 中编写代码,并且刚刚开始研究 Python 3)。

标签: pythonpython-3.xcombinationscombinatoricscartesian-product

解决方案


比使用setuniquify 的结果更好product,您可以直接组合productitertools.combinations_with_replacement产生您关心的结果:

from itertools import product, combinations_with_replacement as comb_repl

[p1 + p2 for p1, p2 in product(comb_repl([1, 2], 2), comb_repl([5, 6], 2))]

这会产生所需的准确输出,没有重复(因此不需要单独的重复数据删除步骤)。

请注意,除了传递给 的第一个迭代器之外,所有的迭代器productproduct将缓存迭代器,因此在这种情况下,完整的输出comb_repl([5, 6], 2)最终将存储在内存中,以及tuple您实际需要的所有四个。在这种情况下这很好,但如果您的组合集明显更大,您可能更愿意随时重新计算组合,因此您只需为最终结果支付内存,而不是combinations_with_replacement为第二个迭代器支付完整的输出集。由于product缓存,您必须避免它,使用for重复创建第二个combinations_with_replacement迭代器的多列表推导:

# Also switched argument to second comb_repl to a tuple, so argument is not repeatedly rebuilt;
# slightly less readable due to profusion of parens, but equivalent behavior
[p1 + p2 for p1 in comb_repl([1, 2], 2) for p2 in comb_repl((5, 6), 2)]

product在测试中,嵌套循环 listcomp 比在不关心内存时使用稍慢(product将更多工作推到 C 层,并且只创建两个实例combinations_with_replacement,而不是第一个迭代器的每个输出加一个;在第二个和随后的传递,它正在迭代tuple输出的缓存,这与 Python 获得的速度一样快),所以如果你知道你的参数不会变得足够大以至于product缓存无关紧要,那么 usingproduct可以获得最佳性能。

在所有情况下,除非你真的需要一个已实现list的,否则最好使用一个生成器表达式(genexpr),因为一个genexpr 只在被询问时产生结果,并且不必将它们全部存储在内存中;你可以循环一次,然后它就用尽了,但在很多情况下,你只需要循环一次就完成了。使用genexpr,用法如下所示:

# Outer square brackets changed to parentheses
products = (p1 + p2 for p1 in comb_repl([1, 2], 2) for p2 in comb_repl((5, 6), 2))
for p in products:
    ... do stuff with one output ...

不再复杂,并且对于更大的组合,不会耗尽内存。


推荐阅读