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

Ada*_*dam 58 python

我有一个列表(简单说6个元素)

L = [0, 1, 2, 3, 4, 5]
Run Code Online (Sandbox Code Playgroud)

我想块成在对所有可能的方式.我展示了一些配置:

[(0, 1), (2, 3), (4, 5)]
[(0, 1), (2, 4), (3, 5)]
[(0, 1), (2, 5), (3, 4)]
Run Code Online (Sandbox Code Playgroud)

等等.这里(a, b) = (b, a)和对的顺序并不重要,即

[(0, 1), (2, 3), (4, 5)] = [(0, 1), (4, 5), (2, 3)]
Run Code Online (Sandbox Code Playgroud)

这样的配置的总数是1*3*5*...*(N-1)哪里N是我的列表的长度.

如何在Python中编写一个生成器,为我提供任意可能的配置N

Mat*_*ner 83

看看itertools.combinations.

matt@stanley:~$ python
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 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)]
Run Code Online (Sandbox Code Playgroud)

  • 这不是问题的问题......但确实恰好是我正在寻找的:) (34认同)
  • 它回答了大多数人来到这个网站的问题. (10认同)
  • 为什么这是最受好评的答案?它似乎无法回答问题。 (3认同)
  • @Halbort它确实回答了标题,所以它对很多人有帮助.另外,这无疑是OP的主要问题.这是*一个可迭代*的组合,现在你想要它的块. (2认同)

sha*_*ang 30

我认为标准库中没有任何功能能够满足您的需求.只是使用itertools.combinations可以获得所有可能的单个对的列表,但实际上并没有解决所有有效对组合的问题.

你可以通过以下方式轻松解决

import itertools
def all_pairs(lst):
    for p in itertools.permutations(lst):
        i = iter(p)
        yield zip(i,i)
Run Code Online (Sandbox Code Playgroud)

但这会让你重复,因为它将(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
Run Code Online (Sandbox Code Playgroud)

它是递归的,所以它会遇到一个包含长列表的堆栈问题,但是否则可以满足您的需求.

>>> 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)]

  • 默认情况下,Python有一个返回堆栈1000深度调用.您正在对数字对进行递归,因此在您的列表长度近2000个项目之前,这不应该是一个问题.只有50件商品可以获得5*10 ^ 31以上的组合; 在堆栈深度成为问题之前很久你就会遇到数十亿年的计算. (13认同)
  • @MoritzWalter对于奇数长度的输入列表,您期望输出是什么?对我来说,如果列表的长度是奇数,这个问题甚至没有意义,因为它不能分成对。 (3认同)
  • 这是编写此代码的经典方法。 (2认同)
  • 抱歉,我确定答案是出于最好的意图而写的,但是对于所有奇数长度的输入列表来说都是不正确的 (2认同)

lef*_*rav 13

这个怎么样:

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')]
Run Code Online (Sandbox Code Playgroud)

要么

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)]
Run Code Online (Sandbox Code Playgroud)

  • 好吧,它不会对成对的集合进行分组 (2认同)

mel*_*des 9

一个非递归函数,用于查找所有可能的对,其中顺序无关紧要,即 (a,b) = (b,a)

def combinantorial(lst):
    count = 0
    index = 1
    pairs = []
    for element1 in lst:
        for element2 in lst[index:]:
            pairs.append((element1, element2))
        index += 1

    return pairs
Run Code Online (Sandbox Code Playgroud)

由于它是非递归的,因此您不会遇到长列表的内存问题。

使用示例:

my_list = [1, 2, 3, 4, 5]
print(combinantorial(my_list))
>>>
[(1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)]
Run Code Online (Sandbox Code Playgroud)

  • 这与 itertools.combinations 相同 (4认同)

tok*_*and 8

在概念上类似于@ shang的答案,但它不假设组的大小为2:

import itertools

def generate_groups(lst, n):
    if not lst:
        yield []
    else:
        for group in (((lst[0],) + xs) for xs in itertools.combinations(lst[1:], n-1)):
            for groups in generate_groups([x for x in lst if x not in group], n):
                yield [group] + groups

pprint(list(generate_groups([0, 1, 2, 3, 4, 5], 2)))
Run Code Online (Sandbox Code Playgroud)

这会产生:

[[(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)]]
Run Code Online (Sandbox Code Playgroud)


Ade*_*mro 6

尝试以下递归生成器函数:

def pairs_gen(L):
    if len(L) == 2:
        yield [(L[0], L[1])]
    else:
        first = L.pop(0)
        for i, e in enumerate(L):
            second = L.pop(i)
            for list_of_pairs in pairs_gen(L):
                list_of_pairs.insert(0, (first, second))
                yield list_of_pairs
            L.insert(i, second)
        L.insert(0, first)
Run Code Online (Sandbox Code Playgroud)

用法示例:

>>> for pairs in pairs_gen([0, 1, 2, 3, 4, 5]):
...     print pairs
...
[(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)]
Run Code Online (Sandbox Code Playgroud)


gat*_*ado 5

我的老板可能不会很高兴我花一点时间解决这个有趣的问题,但是这里有一个很好的解决方案,不需要递归就可以使用itertools.product。在文档字符串中有解释:)。结果似乎还可以,但是我还没有对其进行太多测试。

import itertools


def all_pairs(lst):
    """Generate all sets of unique pairs from a list `lst`.

    This is equivalent to all _partitions_ of `lst` (considered as an indexed
    set) which have 2 elements in each partition.

    Recall how we compute the total number of such partitions. Starting with
    a list

    [1, 2, 3, 4, 5, 6]

    one takes off the first element, and chooses its pair [from any of the
    remaining 5].  For example, we might choose our first pair to be (1, 4).
    Then, we take off the next element, 2, and choose which element it is
    paired to (say, 3). So, there are 5 * 3 * 1 = 15 such partitions.

    That sounds like a lot of nested loops (i.e. recursion), because 1 could
    pick 2, in which case our next element is 3. But, if one abstracts "what
    the next element is", and instead just thinks of what index it is in the
    remaining list, our choices are static and can be aided by the
    itertools.product() function.
    """
    N = len(lst)
    choice_indices = itertools.product(*[
        xrange(k) for k in reversed(xrange(1, N, 2)) ])

    for choice in choice_indices:
        # calculate the list corresponding to the choices
        tmp = lst[:]
        result = []
        for index in choice:
            result.append( (tmp.pop(0), tmp.pop(index)) )
        yield result
Run Code Online (Sandbox Code Playgroud)

干杯!