从Python列表中产生约束组合对的最有效方法

时间:2019-10-01 11:00:20

标签: python list combinations combinatorics

我需要遍历项目列表(a, b)中的长度为2的组合对(c, d)l,并具有以下约束:

  1. 不可成对重复:如果已经出现(a, b),则不会产生(b, a)
  2. 线对之间没有重复,也就是说,线对只能考虑一次:如果(a, b)(c, d)已经出现,那么(c, d)(a, b)将不会产生 li>
  3. 两对中的项目必须不同:a != c and a != d and b != c and b != d

例如,使用

l = [0, 1, 2, 3, 4]

这对应该是:

(0, 1), (2, 3)
(0, 1), (2, 4)
(0, 1), (3, 4)

(0, 2), (1, 3)
(0, 2), (1, 4)
(0, 2), (3, 4)

(0, 3), (1, 2)
(0, 3), (1, 4)
(0, 3), (2, 4)

(0, 4), (1, 2)
(0, 4), (1, 3)
(0, 4), (2, 3)

(1, 2), (3, 4)
(1, 3), (2, 4)
(1, 4), (2, 3)

在示例中我使用了整数,但是,我对更通用的解决方案感兴趣(尽管在我的特定情况下,这些项是列表)。

这是我想出的解决方案:

import itertools

used = set()

for (a, b) in itertools.combinations(l, 2):
    used.add((a, b))
    for (c, d) in itertools.combinations(l, 2):
        if a == c or a == d or b == c or b == d:
            continue
        if (c, d) in used:
            continue
        # do stuff...
        pass

除了麻烦之外,此解决方案还需要附加集used。在实际的实现中,我使用enumerate(l)而不是l并将项目的索引放在集合中的元组中,并尝试使用索引更快地过滤选项...但是没有进行管理使其变得更好。

如何使它更高效,并且可能更优雅/ Pythonic?

1 个答案:

答案 0 :(得分:2)

一个想法可能是首先生成元组的所有组合,然后对其进行过滤:

l = [0, 1, 2, 3, 4]
aa = list(itertools.combinations(list(itertools.combinations(l, 2)), 2))
[(a,b) for a,b in aa if set(a).isdisjoint(b)]