如何将列表按所有可能的方式分成对

133 投票
14 回答
143618 浏览
提问于 2025-04-16 14:00

我有一个列表(为了简单起见,假设有6个元素)

L = [0, 1, 2, 3, 4, 5]

我想把它分成成对的组合,且要考虑所有可能的方式。我展示了一些组合:

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

等等。在这里,(a, b) = (b, a),也就是说,成对的顺序并不重要,也就是

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

这样的组合总数是 1*3*5*...*(N-1),其中 N 是我列表的长度。

我该如何在Python中写一个生成器,来给我所有可能的组合,适用于任意的 N 呢?

14 个回答

32

这样怎么样:

items = ["me", "you", "him"]
[(items[i],items[j]) for i in range(len(items)) for j in range(i+1, len(items))]

[('me', 'you'), ('me', 'him'), ('you', 'him')]

或者

items = [1, 2, 3, 5, 6]
[(items[i],items[j]) for i in range(len(items)) for j in range(i+1, len(items))]

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

我觉得标准库里没有一个函数能完全满足你的需求。用 itertools.combinations 可以得到所有可能的单独配对,但这并不能解决所有有效配对组合的问题。

你可以很简单地用以下代码来解决这个问题:

import itertools
def all_pairs(lst):
    for p in itertools.permutations(lst):
        i = iter(p)
        yield zip(i,i)

不过这样做会出现重复,因为它把 (a,b) 和 (b,a) 当作不同的配对,而且还会给出配对的所有排列方式。最后我发现,自己从头写这个代码比试图过滤结果要简单,所以这里是正确的函数。

def all_pairs(lst):
    if len(lst) < 2:
        yield []
        return
    if len(lst) % 2 == 1:
        # Handle odd length list
        for i in range(len(lst)):
            for result in all_pairs(lst[:i] + lst[i+1:]):
                yield result
    else:
        a = lst[0]
        for i in range(1,len(lst)):
            pair = (a,lst[i])
            for rest in all_pairs(lst[1:i]+lst[i+1:]):
                yield [pair] + rest

这个函数是递归的,所以如果列表很长可能会出现栈溢出的问题,但除此之外,它能满足你的需求。

>>> for x in all_pairs([0,1,2,3,4,5]):
    print x

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

看看这个链接:itertools.combinations,这里面介绍了一个叫做`itertools.combinations`的东西。

>>> import itertools
>>> list(itertools.combinations(range(6), 2))
[(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)]

撰写回答