给出了一个元素列表。我希望有可能将此列表划分为任意数量的分区,以便每个分区至少有 x 个元素。列表中分区的顺序和分区中元素的顺序无关紧要。例如: List = [1,2,3,4] get_partitions(list,2) 应该返回:
[[1,2,3,4],
[[1,2],[3,4]],
[[1,3],[2,4]],
[[1,4],[2,3]]]
List = [1,2,3,4] get_partitions(list,1) 应该返回:
[[1,2,3,4],
[[1,2],[3,4]],
[[1,3],[2,4]],
[[1,4],[2,3]],
[[1],[2],[3,4],
...]
我已经开始在 Python 中递归地实现这个,但是我创建了太多的冗余案例。例如,出于运行时的原因,我想提前减少这些情况,而不是在之后使用 freezesets 删除它们。
from itertools import combinations
import numpy as np
def get_partitions(liste,min,max=None):
if max is None:
# Default setting
max = len(liste)
if len(liste) == min :
# Termination Criterium
yield [liste]
else:
for r in range(np.min([len(liste),max]),min-1,-1):
# max for avoiding cases like: [[1,2,3,4],[2,6]] and [[2,6],[1,2,3,4]]
for perm in combinations(liste,r):
rest = [i for i in liste if i not in perm]
if len(rest) >= min:
for recurse in get_partitions(rest,min,r):
yield [list(perm)] + list(recurse)
if len(rest) == 0:
# r == len(liste)
yield [list(perm)]
这将导致:
[[[1, 2, 3, 4]],
[[1, 2], [3, 4]],
[[1, 3], [2, 4]],
[[1, 4], [2, 3]],
[[2, 3], [1, 4]],
[[2, 4], [1, 3]],
[[3, 4], [1, 2]]]
提前感谢您的帮助。
尝试使用@mozway 的答案并将其扩展到递归版本导致我:
def get_partitions(iterable, minl=2):
s = set(iterable)
for r in range(minl, len(s)//2+1):
if len(s)//2 != r:
for c in combinations(s, r):
for recurse in get_partitions(list(s.difference(c)), minl):
yield [list(c),*recurse]
else:
for c in islice(combinations(s, r), comb(len(s),r)//2):
for recurse in get_partitions(list(s.difference(c)), minl):
yield [list(c),*recurse]
yield [list(s)]
对于示例 list = [1,2,3,4], x=1 它正在将可能性的数量从 47(我最初的尝试)减少到 19。仍然有很多多余的情况。
[[[1], [2], [3], [4]], <----
[[1], [2], [3, 4]],
[[1], [2, 3, 4]],
[[2], [1], [3], [4]], <----
[[2], [1], [3, 4]],
[[2], [1, 3, 4]],
[[3], [1], [2], [4]], <----
[[3], [1], [2, 4]],
[[3], [1, 2, 4]],
[[4], [1], [2], [3]], <----
[[4], [1], [2, 3]],
[[4], [1, 2, 3]],
[[1, 2], [3], [4]],
[[1, 2], [3, 4]],
[[1, 3], [2], [4]],
[[1, 3], [2, 4]],
[[1, 4], [2], [3]],
[[1, 4], [2, 3]],
[[1, 2, 3, 4]]]