簡體   English   中英

python中L組K項中N個元素的組合

[英]Combination of N elements in L groups of K items in python

給定一個包含 N 個元素的列表,例如

mylist = [0, 1, 2, 3, 4, 5, 6, 7]

我想找到 L 組中 K 元素的所有組合,例如對於K=4 , L=2 ,結果為

          L=0            L=1 
 1)   [0, 1, 2, 3]   [4, 5, 6, 7]
 2)   [0, 1, 2, 4]   [3, 5, 6, 7]
 3)   [0, 1, 2, 5]   [3, 4, 6, 7]

              ... etc...
69)   [4, 5, 6, 7]   [0, 1, 2, 3]

請注意, [0, 1, 2, 3][0, 1, 3, 2]將被視為第一組的相同組合。

對於L=2的情況,我使用以下

from itertools import combinations

N = 8
M = 4
L = N // M

combs = list(combinations(range(N), M))
allidx = list(range(N))

for c, comb in enumerate(combs):

    idx1 = list(comb)
    idx2 = list(set(allidx) - set(idx1))

    print(c, idx1,'\t',idx2)

首先,這種“組合”的數學定義是什么?

其次,在L>2的情況下,是否有比計算所有排列並在之后修剪它們更有效的方法來計算它們?

您可以使用遞歸函數,從列表中獲取k元素的所有組合,並將它們與其余元素的組合組合。

import itertools

def combs(lst, k, l):
    if l == 0:
        yield []
    else:
        for c in itertools.combinations(lst, k):
            rest = [x for x in lst if x not in c]
            for res in combs(rest, k, l-1):
                yield [c, *res]

mylist = [0, 1, 2, 3, 4, 5, 6, 7]
for res in combs(mylist, 4, 2):
    print(res)

在這里,部分rest = [x for x in lst if x not in c]僅在列表中的元素是唯一的情況下才有效。 如果可以有重復的元素,您可以改為只獲取索引的組合,例如像這樣(其余部分保持不變):

        for idc in itertools.combinations(range(len(lst)), k):
            comb = [lst[i] for i in idc]
            idc_set = set(idc)
            rest = [x for i, x in enumerate(lst) if i not in idc_set]
            for res in combs(rest, k, l-1):
                yield [comb, *res]

(另外,這里假設lst至少有l*k元素。)

這是從長度為 n 的集合中生成所有大小為 k 的唯一分區的方法。

此類分區的數量是(p 是零件的數量,等於您的 L):

NPK(n,k) = n! / ((k!)^p * p!)

並且增長很快(n=9,k=3 時為 280)。

算法以遞歸方式將項目分布到各個部分。 為了避免重復生成相同的分區(如01 23 4501 45 23 ),我們應該限制每個組的前導(最小)元素的位置。

在這里,我使用lastfilled參數作為最右邊填充部分的索引,因此項目 0 始終屬於第 0 部分,項目 1 可能屬於第 0 部分或第 1 部分,但不屬於第 2 部分,依此類推。 有了中間結果01 __ __我們只能在下一級得到01 2_ __ ,而不是01 __ 2_

def genp(l, parts, cnts, n, k, p,  m, lastfilled):
    if m == n:
        l.append(parts[:])
        return
    for i in range(min(p, lastfilled + 2)):
        if cnts[i] < k:
            parts[i][cnts[i]] = m
            cnts[i] += 1
            genp(l, parts, cnts, n, k, p, m+1, max(i, lastfilled))
            cnts[i] -= 1


def genpartssizek(n, k):
    l = []
    p = n // k
    parts = [[0]*k for _ in range(p)]
    cnts = [0]*p
    genp(l, parts, cnts, n, k, p,  0, -1)
    return l

print(genpartssizek(6,2))

[[[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, 4], [1, 2], [3, 5]], 
 [[0, 5], [1, 2], [3, 4]], 
 [[0, 3], [1, 4], [2, 5]], 
 [[0, 3], [1, 5], [2, 4]], 
 [[0, 4], [1, 3], [2, 5]], 
 [[0, 5], [1, 3], [2, 4]], 
 [[0, 4], [1, 5], [2, 3]], 
 [[0, 5], [1, 4], [2, 3]]]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM