两个列表的差异的所有组合

时间:2013-10-02 20:21:01

标签: python combinatorics

我有两个列表,一个是规范的好的列表,另一个是当前的错误的列表。我想尝试列表与列表的所有偏差组合。例如:

good = (0,1,2,3)
bad =  (0,10,20,3)

应用运算符op(good, bad)之后,我应该回来

ret = ((0,1,2,3), (0,10,2,3), (0,10,20,3), (0,1,20,3))

以子列表的任何顺序。

我正在使用的列表是stty -g的输出,它是36个元素,列表相差16个元素。

2 个答案:

答案 0 :(得分:3)

压缩好的和坏的列表,将每个生成的元组映射到一个集合并将其提供给itertools.product()

from itertools import product

for combo in product(*map(set, zip(good, bad))):
    print(combo)

演示:

>>> good = (0,1,2,3)
>>> bad =  (0,10,20,3)
>>> from itertools import product
>>> for combo in product(*map(set, zip(good, bad))):
...     print(combo)
... 
(0, 1, 2, 3)
(0, 1, 20, 3)
(0, 10, 2, 3)
(0, 10, 20, 3)

这将采用任何大小的输入;不仅仅是goodbad,还可以添加ugly

>>> ugly =  (1,2,4,3)
>>> for combo in product(*map(set, zip(good, bad, ugly))):
...     print(combo)
... 
(0, 1, 4, 3)
(0, 1, 2, 3)
(0, 1, 20, 3)
(0, 10, 4, 3)
(0, 10, 2, 3)
(0, 10, 20, 3)
(0, 2, 4, 3)
(0, 2, 2, 3)
(0, 2, 20, 3)
(1, 1, 4, 3)
(1, 1, 2, 3)
(1, 1, 20, 3)
(1, 10, 4, 3)
(1, 10, 2, 3)
(1, 10, 20, 3)
(1, 2, 4, 3)
(1, 2, 2, 3)
(1, 2, 20, 3)

推广到函数:

def op(*sequences):
    return product(*map(set, zip(*sequences)))

for combo in op(good, bad):
    print(combo)

for combo in op(good, bad, ugly):
    print(combo)

因为set用于从每个组合输入中生成唯一值,所以输出顺序与输入顺序不同。如果订单很重要,您可以使用dupe-removing order-preserving function代替set

def unique_with_order(seq):
    seen = set()
    seen_add = seen.add
    return [x for x in seq if x not in seen and not seen_add(x)]

def ordered_op(*sequences):
    return product(*map(unique_with_order, zip(*sequences)))

根据输入的顺序产生排序:

>>> for combo in ordered_op(good, bad):
...     print(combo)
... 
(0, 1, 2, 3)
(0, 1, 20, 3)
(0, 10, 2, 3)
(0, 10, 20, 3)
>>> for combo in ordered_op(bad, good):
...     print(combo)
... 
(0, 10, 20, 3)
(0, 10, 2, 3)
(0, 1, 20, 3)
(0, 1, 2, 3)

答案 1 :(得分:2)

你想要的是每个指数的好坏价值的笛卡尔积,除了当好的和坏的具有相同的价值时,你只需要其中一个,而不是两个副本。

所以,让我们将这两个列表压缩,并将good == bad的每个组件减少为单个值:

>>> gb = (([g,b] if g!=b else [g] for (g, b) in zip(good, bad))

然后是笛卡尔积:

>>> ret = itertools.product(*gb)

因为你想要它作为一个元组:

>>> ret = tuple(ret)
>>> print ret
((0, 1, 2, 3), (0, 1, 20, 3), (0, 10, 2, 3), (0, 10, 20, 3))