首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >所有分组排列内置函数

问所有分组排列内置函数
EN

Stack Overflow用户
提问于 2022-05-23 00:02:40
回答 1查看 116关注 0票数 1

我需要创建一个由4组3个数字组成的所有可能集合的列表,因此每个组集都有12个数字(4 *3= 12)。例如,用数字

代码语言:javascript
复制
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

一个可能的集合是

代码语言:javascript
复制
((1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12))

另一个是

代码语言:javascript
复制
((4, 3, 6), (1, 5, 7), (2, 8, 11), (9, 10, 12))

所以这两个集合应该在排列数组中。排列数组应该如下所示

代码语言:javascript
复制
(((4, 3, 6), (1, 5, 7), (2, 8, 11), (9, 10, 12)), (((1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)), ...)

还有“.”当然,这意味着还有更多的组集。

然而,秩序确实很重要。因为这个,

代码语言:javascript
复制
((6, 4, 3), (7, 1, 5), (11, 2, 8), (9, 12, 10))

和

代码语言:javascript
复制
((9, 10, 12), (2, 11, 8), (1, 7, 5), (3, 6, 4))

都和

代码语言:javascript
复制
((4, 3, 6), (1, 5, 7), (2, 8, 11), (9, 10, 12))

具体来说,如果组的排序或组内事物的排序是不同的,则仍然是同一组组。

一种方法是执行12嵌套for循环(3 *4= 12),但我希望使用内置函数。有人能帮忙吗?

注意:我把括号放在括号数组的二维元组中,每个组设置一个一维元组,但它不一定是元组。它可以是一个列表,列表,元组,等等。

注2:我想要的时间复杂度最多为O(N!),在这里,N= 12。

EN

回答 1

Stack Overflow用户

发布于 2022-05-23 00:52:08

这是一种方法:用itertools.combinations把东西切成两半,然后再用它把一半切成两半。

代码语言:javascript
复制
from itertools import combinations, product

def splittings(numbers):
    numbers = frozenset(numbers)
    assert len(numbers) == 12

    result = set()

    for AB in map(frozenset, combinations(numbers, 6)):
        CD = numbers - AB

        first_half_splittings = []
        for A in map(frozenset, combinations(AB, 3)):
            B = AB - A
            first_half_splittings.append((A, B))

        second_half_splittings = []
        for C in map(frozenset, combinations(CD, 3)):
            D = CD - C
            second_half_splittings.append((C, D))
        
        for A_B, C_D in product(first_half_splittings, second_half_splittings):
            result.add(frozenset(A_B + C_D))

    return [tuple(map(tuple, splitting)) for splitting in result]

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
for split in splittings(numbers):
    print(split)

这最终会导致每分裂4!=24次,但这可以用一组冻结来解决。

这里可能会有更多的优化,例如,总是将第一个值分配给第一个bin,然后将剩下的11个分配到5+6中,但这应该是一个不错的起点。

编辑:下面是这样一个优化的实现,它使我们更容易理解IMO。

代码语言:javascript
复制
from itertools import combinations, product, starmap
from operator import add

def pair_splittings(numbers, k):
    n0, *rest = numbers
    rest = frozenset(rest)
    for B in combinations(rest, len(numbers) - k):
        A = (n0,) + tuple(rest - frozenset(B))
        yield (A, B)

def splittings(numbers):
    assert len(numbers) == 12
    for AB, CD in pair_splittings(numbers, 6):
        first_halves = pair_splittings(AB, 3)
        second_halves = pair_splittings(CD, 3)
        half_choices = product(first_halves, second_halves)
        yield from starmap(add, half_choices)

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
for split in splittings(numbers):
    print(split)

Edit2:一种更通用的解决方案,可以概括为不同数量的回收箱。

代码语言:javascript
复制
from itertools import combinations, product, starmap
from operator import add

def pair_splittings(numbers, k):
    n0, *rest = numbers
    rest = frozenset(rest)
    for B in combinations(rest, len(numbers) - k):
        A = (n0,) + tuple(rest - frozenset(B))
        yield (A, B)

def splittings(elements, num_bins):
    assert len(elements) % num_bins == 0
    bin_size = len(elements) // num_bins

    if num_bins == 1:
        yield (tuple(elements),)
        return

    k = num_bins // 2
    for half1, half2 in pair_splittings(elements, k*bin_size):
        
        # Option 1: a little bit eager. ##############################
        # Here, product() stores both sequences that it's
        # iterating through. This is much faster than re-computing
        # half2_splittings over and over. Note that storing both
        # halves is much less memory than storing their entire product,
        # so this is still somewhat lazy.

        half1_splittings = splittings(half1, k)
        half2_splittings = splittings(half2, num_bins-k)
        half_choices = product(half1_splittings, half2_splittings)
        yield from starmap(add, half_choices)

        # Option 2: extra-lazy. ##############################
        # If you're dealing with bigger numbers and minimal memory,
        # this might be a better aproach.

        # for choices1 in splittings(half1, k):
        #     for choices2 in splittings(half2, num_bins-k):
        #         yield choices1 + choices2

for x in splittings(range(12), 4):
    print(x)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72342083

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档