[英]Split a list into n sublists in all possible ways
I want to split a list into a given number n sublists in all possible ways in Java.我想在 Java 中以所有可能的方式将列表拆分为给定数量的 n 个子列表。
For example [1, 2, 3, 4]
where n = 3 would include the following lists (but would not be a complete solution - complete would require much more space):例如
[1, 2, 3, 4]
其中 n = 3 将包括以下列表(但不是完整的解决方案 - 完整将需要更多空间):
([], [], [1,2,3,4])
([],[1],[2,3,4])
([],[1,2],[3,4])
([],[1,2,3],[4])
([],[1,2,3,4],[])
([1],[2,3,4], [])
([1],[2,3],[4])
([2,3],[4],[1])
([4],[],[1,2,3])
...
etc ETC
I adapted a solution from another similar question ( Split a list into two sublists in all possible ways ) however it only works for creating lists of 2 sublists and I am struggling to grasp how to implement it for a flexible rather than hardcoded number of sublists.我改编了另一个类似问题的解决方案( 以所有可能的方式将列表拆分为两个子列表)但是它仅适用于创建 2 个子列表的列表,我正在努力掌握如何实现它以实现灵活而不是硬编码的子列表数量。
Here is my code:这是我的代码:
public List<List<EGroup>> permutation(List<E> list) {
List<List<E>> sublists = new ArrayList<List<E>>();
for (int i = 0; i <= list.size(); i++) {
permutationSplit(list, sublists, i, new ArrayList<E>(), 0);
}
List<List<EGroup>> listOfEGroupPairs = new ArrayList<List<EGroup>>();
for (List<E> subList : sublists) {
List<E> listCopy = new ArrayList<E>(list);
listCopy.removeAll(subList);
EGroup e1 = new EGroup(subList);
EGroup e2 = new EGroup(listCopy);
List<EGroup> egr = new ArrayList<EGroup>();
egr.add(e1);
egr.add(e2);
listOfEGroupPairs.add(egr);
}
return listOfEGroupPairs;
}
public void permutationSplit(List<E> list, List<List<E>> subLists, int sublistSize, List<E> currentSubList,
int startIndex) {
if (sublistSize == 0) {
subLists.add(currentSubList);
} else {
sublistSize--;
for (int i = startIndex; i < list.size(); i++) {
List<E> newSubList = new ArrayList<E>(currentSubList);
newSubList.add(list.get(i));
permutationSplit(list, subLists, sublistSize, newSubList, i + 1);
}
}
}
I need to create n number of EGroup objects to add to listOfEGroupPairs
rather than the hardcoded 2, but how to always get the right number (n) of sublists of varied size each loop?我需要创建 n 个 EGroup 对象以添加到
listOfEGroupPairs
而不是硬编码的 2,但是如何始终在每个循环中获得正确数量 (n) 的不同大小的子列表?
You have K
elements and each might fall into any of N
lists.您有
K
个元素,每个元素都可能属于N
个列表中的任何一个。 So there are N^K
variants and we can just map integer values from 0
to N^K-1
to distributions like N-ary numeral system.所以有
N^K
变体,我们可以只 map integer 值从0
到N^K-1
到像 N 进制数字系统这样的分布。
Another approach - recursively insert every element into N lists.另一种方法 - 递归地将每个元素插入到 N 个列表中。
I can demonstrate approaches with Python code recursive , N-ary and hope it might be translated to Java我可以使用 Python 代码递归、 N-ary来演示方法,并希望它可以转换为 Java
def recdistr(K, N, level, ls):
if level == K:
print(ls)
else:
for i in range(N):
ls[i].append(level)
recdistr(K, N, level + 1, ls) #recursive call with changed list
ls[i].pop() #remove last added element to revert list to previous state
K = 4
N = 3
lst = [[] for _ in range(N)]
recdistr(K, N, 0, lst)
def mapdistr(K, N):
for x in range(N**K):
t = x
l = [[] for _ in range(N)]
for i in range(K):
id = t % N
t = t // N #integer division
l[id].append(i)
print(l)
mapdistr(K, N)
If I understand the question correctly, each element of the original list can end up in any of the n
sublists.如果我正确理解了这个问题,原始列表的每个元素都可以在
n
个子列表中的任何一个中结束。 That means, there are n^s
possible sublists ( s
being the number of elements in the original list), which can be enumerated in a simple loop.这意味着,有
n^s
可能的子列表( s
是原始列表中的元素数),可以在一个简单的循环中枚举。 With a bit of modulo and integer division you can then get the proper "bucket" for each element and prepare the results accordingly.通过一些模数和 integer 除法,您可以获得每个元素的正确“桶”并相应地准备结果。
public <T> List<List<List<T>>> partition(List<T> lst, int n) {
var result = new ArrayList<List<List<T>>>();
// k = SUM ( pos of lst[i] * n^i )
for (int k = 0; k < Math.pow(n, lst.size()); k++) {
// initialize result
List<List<T>> res = IntStream.range(0, n)
.mapToObj(i -> new ArrayList<T>())
.collect(Collectors.toList());
// distribute elements to sub-lists
int k2 = k;
for (int i = 0; i < lst.size(); i++) {
res.get(k2 % n).add(lst.get(i));
k2 /= n;
}
result.add(res);
}
return result;
}
Use recursion.使用递归。
For n
equal to 0 or negative the task is impossible.对于
n
等于 0 或负数,该任务是不可能的。 Either throw an exception or return an empty lists of lists of sublists.抛出异常或返回子列表列表的空列表。 Corner case: if
n
is 0 and the list is empty, you may argue that the empty list of sublists is a valid response.极端情况:如果
n
为 0 并且列表为空,您可能会争辩说子列表的空列表是有效响应。
If n
is 1, the only solution is trivially the entire list.如果
n
为 1,唯一的解决方案就是整个列表。
For n > 1
:对于
n > 1
:
If the length of the list is 4 (for example [1, 2, 3, 4]
), there are 5 possible first lists.如果列表的长度为 4(例如
[1, 2, 3, 4]
),则有 5 个可能的第一个列表。 In general there are list.length + 1
possible first sublists.通常有
list.length + 1
可能的第一个子列表。 Find them.找到他们。 For each such sublist make a recursive call passing the remainder of the list and
n - 1
as arguments to find all possible combinations of sublists made from the remainder of the list.对于每个这样的子列表,进行递归调用,将列表的其余部分和
n - 1
作为 arguments 以查找从列表的其余部分组成的子列表的所有可能组合。 Combine each first sublist with each combination of remaining sublists to form a full solution.将每个第一个子列表与剩余子列表的每个组合结合起来,形成一个完整的解决方案。
Happy coding.快乐编码。
PS The solution as sketched will only produce sublists in the order they come in the original list. PS 草图中的解决方案只会按照它们在原始列表中的顺序生成子列表。 So the solution will include
([],[1],[2,3,4])
and ([1],[2,3,4], [])
, but not ([4],[],[1,2,3])
.所以解决方案将包括
([],[1],[2,3,4])
和([1],[2,3,4], [])
,但不包括([4],[],[1,2,3])
。 To regard the last one as a separate solution, you will additionally need to find all permutations of each solution, in turn taking into account that some sublists may be equal and hence swapping them won't make a distinct solution.要将最后一个视为单独的解决方案,您还需要找到每个解决方案的所有排列,进而考虑到某些子列表可能相等,因此交换它们不会产生不同的解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.