【问题标题】:itertools product should not contain combination having duplicate valuesitertools 产品不应包含具有重复值的组合
【发布时间】:2016-07-02 11:55:14
【问题描述】:

我正在尝试创建组合。示例代码如下:

a = [1, 2, 3], [1, 4, 5]
combinations = list(itertools.product(*a))

输出:

[(1, 1), (1, 4), (1, 5), (2, 1), (2, 4), (2, 5), (3, 1), (3, 4), (3, 5)]

我不需要组合(1,1)。 我已经尝试过以下代码:

for comb in combinations:
    if comb[0] == comb[1]:
        combinations.remove(comb)

但是因为我必须对大量数据执行此操作。时间太长了。

此外,组合的元素应该等于列表中的项目数。 例如:a = [1,2,3], [2,3,7],[4,5,1] 每个组合中的元素为 3,例如 (1,2,4)

请提出一种避免此类组合的方法。

【问题讨论】:

  • 您是否只想避免(1, 1, 1)(1, 1, 2)(1, 2, 1)
  • @poke:只需要考虑具有唯一值的组合。所以 (1,1,2) & (1,2,1) 应该被丢弃。

标签: python list combinations


【解决方案1】:

对于两个可迭代对象,一个简单的列表推导可以做到:

>>> from itertools import product
>>> a = [1, 2, 3], [1, 4, 5]
>>> [(x, y) for x, y in product(*a) if x != y]
[(1, 4), (1, 5), (2, 1), (2, 4), (2, 5), (3, 1), (3, 4), (3, 5)]

如果您需要过滤 任意 个可迭代对象的乘积,那么最好使用集合来检查组合的所有元素是否不同:

>>> a = [1, 2, 3], [1, 4, 5], [1, 8, 9]
>>> [p for p in product(*a) if len(set(p)) == len(p)]
[(1, 4, 8), (1, 4, 9), (1, 5, 8), (1, 5, 9), (2, 1, 8), (2, 1, 9), (2, 4, 1), (2, 4, 8), (2, 4, 9), (2, 5, 1), (2, 5, 8), (2, 5, 9), (3, 1, 8), (3, 1, 9), (3, 4, 1), (3, 4, 8), (3, 4, 9), (3, 5, 1), (3, 5, 8), (3, 5, 9)]

顺便说一句,永远不要更改您正在循环的列表,因为这很可能会产生错误的循环。

【讨论】:

  • 谢谢。但是,如果只有两个项目(列表),则此逻辑将起作用。在我的情况下,这些项目可以是多个。例如。 [1,2,3],[3,4,1],[4,31] 等等。
  • @panr...您要求获得 2 值产品吗?...或者产品的尺寸是多少?...您应该在问题中包含此信息
【解决方案2】:

如果您的列表列表可以有两个以上的子列表,您可以将元组的大小与将元组转换为set 后的大小进行比较,从而过滤重复元素。

>>> import itertools
>>> b = [1,2,3],[1,4,5],[1,2,6]
>>> [x for x in itertools.product(*b) if len(x) == len(set(x))]
[(1, 4, 2), (1, 4, 6), (1, 5, 2), (1, 5, 6), 
 (2, 1, 6), (2, 4, 1), (2, 4, 6), (2, 5, 1), (2, 5, 6), 
 (3, 1, 2), (3, 1, 6), (3, 4, 1), (3, 4, 2), (3, 4, 6), (3, 5, 1), (3, 5, 2), (3, 5, 6)]

当列表数量超过 20 个时,它可以正常工作,但需要的时间太长。[...] 列表的最大数量为 40,每个列表中的项目最多可以达到 20 个。

这些列表非常多且非常大。即使对于每个包含 3 个元素的 20 个列表,您也必须经过 3^20 = 3,486,784,401 种组合。这仍然可行,但您应该使用生成器表达式,而不是列表推导式,即 (...) 而不是 [...]

gen = (x for x in itertools.product(*b) if len(x) == len(set(x)))
for x in gen:
    # do stuff

对于每个包含 20 个元素的 40 个列表,您会得到多达 10^52 个组合。在你生成所有这些之前,宇宙可能会死去。假设大多数(实际上几乎所有)包含重复项,您可以尝试更聪明的算法,在遇到组合时立即跳过整个“分支”第一个副本,但我怀疑即使是那些也会有很大帮助。

【讨论】:

  • 可以正常使用,但是当列表数量超过 20 个时,耗时太长。
  • 超过 20 个?您是否计算过(在纸上或使用计算器)您期望有多少组合?你的数据到底有多大?例如,对于每个列表的 3 个项目,这将是 3^20,即 3,486,784,401 种组合...无论您选择哪种方法,这需要一些时间。
  • 列表的最大数量为 40,每个列表中的项目最多可达到 20 个。
  • 40 个包含 20 个元素的列表,即 10^52 个组合。祝你好运。
【解决方案3】:

这里有 3 种方法可以做到这一点

a = [1,2,3],[1,4,5]
  1. filter(lambda x: x[0] != x[1], [(x,y) for x in a[0] for y in a[1]])
    
  2. combinations = list(itertools.product(*a))
    [value for value in combinations if value[0] != value[1]]
    
  3. filter(lambda x:x[0] != x[1], combinations)
    

【讨论】:

    【解决方案4】:

    像这样编辑代码的第二部分:

    for  comb in combinations:
        if comb[0] == comb[1]:
            combinations.remove(comb)
    

    【讨论】:

    • 在迭代列表时从列表中删除是个坏主意
    猜你喜欢
    • 2015-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多