如果可能的话,使用flatMap在java中将列表拆分为子列表



这是我的列表:

List<Integer> mylist = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12);

假设我的列表总是偶数,那么我想把它分成6等分。

以草图形式列出:

[1,2,3,4,5,6,7,8,9,10,11,12]

输出示意图:

[[1,2][3,4],[5,6],[7,8],[9,10],[11,12]]

如果可能的话,我更喜欢Java 8流flatMap的解决方案

给定;子列表";都是相同大小的,并且您可以将列表划分为相同大小的精确子列表,您可以计算所需的大小,然后将IntStream映射到每个子列表的起始索引,并使用它来提取它们:

List<Integer> mylist = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12);
int size = mylist.size();
int parts = 6;
int partSize = size / parts;
List<List<Integer>> result = 
IntStream.range(0, parts)
.mapToObj(i -> mylist.subList(i * partSize, (i + 1) * partSize)))
.collect(Collectors.toList());

编辑:
Ide@Turing85 优雅地提供了一个演示

我知道它超出了范围,但另一种可能性是使用像Guava这样的库,它有很多与List相关的方法。

依赖性

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>

示例

package com.stackoverflow.question;
import java.util.Arrays;
import java.util.List;
import com.google.common.collect.Lists;
public class Question {
public static void main(String[] args) {
List<Integer> mylist = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12);
List<List<Integer>> partionList = Lists.partition(mylist, 2);

System.out.println(partionList);
}
}

输出

[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]]

Stream-操作应该是无状态的。要执行的任务本质上需要状态。因此,我建议不要使用Stream。相反,我推荐一个基于for循环的解决方案:

public static List<List<Integer>> partition(
List<Integer> list, 
int partitionSize) {
final int listSize = list.size();
if (listSize % partitionSize != 0) {
throw new IllegalArgumentException("The size of the list must be "
+ "divisible without remainder by the partition size.");
}

final List<List<Integer>> partition = new ArrayList<>();
for (int start = 0; start < listSize; start += partitionSize) {
partition.add(list.subList(start, start + partitionSize));
}
return partition;
}

Ideone演示

如果我们坚持使用基于Stream的实现,我建议使用Mureinik给出的代码。

以下内容适用于从1到size of the list的任何组大小。如果组大小没有平均划分列表大小,那么剩余的将被放入自己的组中。

此外,额外的map(ArrayList::new)确保子列表被放入其自己的列表中。否则,更改原始列表条目也将更改子列表条目。

int gsize = 2;
List<Integer> mylist =
Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
List<List<Integer>> subLists = IntStream
.iterate(0, i -> i < mylist.size(),
i -> i + gsize)
.mapToObj(i -> mylist.subList(i,
(i + gsize <= mylist.size()) ?
i + gsize : mylist.size()))
.map(ArrayList::new)
.collect(Collectors.toList());

System.out.println(subLists);

打印

[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]]

如果组大小为5,则新列表将如下所示:

[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12]]

如果你真的想要一个带有flatMap的解决方案,你可以尝试这样的方法,而不是直观的解决方案。最后,它只需要返回一个Stream,所以这只是在它前进的过程中构建子列表,并在最后将其返回为Stream。

顺便说一句,我个人更喜欢Guava的Lists.partition

List result = list.stream().flatMap(new Function<>() {
List<List<Integer>> mainList = new ArrayList<>();
List<Integer> subList = new ArrayList<>(2);
int index = 0;
@Override
public Stream<?> apply(Integer integer) {
subList.add(integer);
if ((index + 1) % 2 == 0) {
mainList.add(subList);
subList = new ArrayList<>(2);
}
index++;
if (index == list.size()) {
if(!subList.isEmpty()) {
mainList.add(subList);
}
return mainList.stream();
}
return Stream.empty();
}
}).collect(Collectors.toList());

最新更新