查找列表中元素数量最少的所有无序分区
给出了元素列表。我希望拥有将这个列表划分为任意数量的分区的所有可能性,以便每个分区至少有 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]]]
A list of elements is given. I want to have all the possibilities to divide this list into any number of partitions so that each partition has at least x elements. The order of the partitions in the list and the order of the elements in the partition do not matter.
E.g.:
List = [1,2,3,4] get_partitions(list,2) should return:
[[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) should return:
[[1,2,3,4],
[[1,2],[3,4]],
[[1,3],[2,4]],
[[1,4],[2,3]],
[[1],[2],[3,4],
...]
I have started to implement this recursively in Python, but I create too many redundant cases. For runtime reasons, I would like to reduce these cases in advance and not delete them afterwards with frozensets, for example.
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)]
This leads to:
[[[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]]]
Thanks in advance for any help.
Trying to use @mozway 's answer and extending it to a recursive version lead me to:
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)]
For the example list = [1,2,3,4], x=1 it is reducing the number of possibilities from 47 (my initial try) to 19. Still, there are plenty of redundant cases.
[[[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]]]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是一个很长的解决方案。在生成分区时不使用拒绝,因此从这个意义上说,这可能有点有效。尽管如此,还有很多东西需要优化。
示例:
以下是其工作原理的概述:
split
函数非常有用,该函数采用列表lst
和整数n
n code> 并返回将列表分为两组的所有方法,一组的大小为 n ,另一组的大小为 len(lst) - n 。lst
拆分为n
个组,每个组的大小为k
。当然,这只有在len(lst) = n * k
时才有可能。这是在get_partitions_same_size
函数中实现的。这个想法是始终将lst
的第一个元素包含在第一组中并递归。len(lst)
的所有整数分区。我从这个线程复制了代码。len(lst)
的每个整数分区p
,我们需要找到所有对lst
进行分区的方法根据p
。len(lst) == 7
和p = 3 + 2 + 2
。在这种情况下,我们可以为第一组选择任意三个元素,为第二组选择任何剩余的两个元素,而对于最后的第三组则无需进行选择。p
对应于p_scheme = [(3, 1), (2, 2)]
。函数get_partitions_helper
接收一个列表lst
和一个“分区方案”p_scheme
,并返回所有相应的分区,而不进行重复计数。这是使用第二步中的get_partitions_same_size
的地方。get_partitions
中:我们循环遍历len(lst)
的整数分区,并返回与每个可能的整数分区相对应的所有可能的列表分区。这是一个有趣的问题,非常欢迎对错误和优化提出评论。
Here is one long-ish solution. No rejection is used in generating partitions, so in that sense this may be somewhat efficient. Still, there are lots of things to optimize.
Example:
Here is an outline of how this works:
split
function that takes a listlst
and an integern
and return all ways to split the list into two groups, one of sizen
and another of sizelen(lst) - n
.lst
inton
groups each of sizek
. Of course, this is only possible whenlen(lst) = n * k
. This is implemented inget_partitions_same_size
function. The idea is to always include the first element oflst
in the first group and recurse.len(lst)
. I copied code from this thread.p
oflen(lst)
, we need to find all ways to partitionlst
according top
.len(lst) == 7
andp = 3 + 2 + 2
. In this case, we can choose any three elements for the first group, any remaining two for the second group, and there is no choice to be made for the final third group.p
corresponds top_scheme = [(3, 1), (2, 2)]
. The functionget_partitions_helper
takes in a listlst
and a "partition scheme"p_scheme
, and returns all corresponding partitions without double-counting. This is whereget_partitions_same_size
from step two is used.get_partitions
: we loop over integer partitions oflen(lst)
and return all possible list partitions corresponding to each possible integer partition.This is a fun problem and comments on bugs and optimizations are very welcome.
这看起来像是带有补集的部分幂集。
您不需要定义最大值,一旦设置了最小值,它就固定了。
另外,包括完整集是一种特殊情况(从技术上讲,完整集是集合+空集,因此它违反了最小条件)
要限制组合的数量,只要拥有总长度的前一半即可。如果您有偶数输入并选择半分区,则仅计算一半的组合(使用itertools.islice):
您可以使用:
输出:
其他示例:
This looks like a partial powerset with a complement.
You do not need to define a max, it is fixed once min is set.
Also, including the full set is a special case (technically a full set is the set + an empty set, so it violates the min condition)
To limit the number of combinations, just stop with you have the first half of the total length. If you have an even input and are picking the half partition, only compute half of the combinations (using
itertools.islice
):You could use:
output:
other example: