在流中有一种简单的方法:
public static void main(String[] args) {
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.print(partitioningValues(integerList, 3));
}
private static Map<Integer, List<Integer>> partitioningValues(List<Integer> integerList, int numberOfPartitions) {
Map<Integer, List<Integer>> integerListMap = new HashMap<>();
BigDecimal limit = BigDecimal.valueOf(integerList.size() / (double) numberOfPartitions);
int limitRounded = limit.setScale(0, BigDecimal.ROUND_UP).intValue();
for (int i = 0; i < numberOfPartitions; i++) {
int toIndex = ((i + 1) * limitRounded) > integerList.size() ? integerList.size() : (i + 1) * limitRounded;
integerListMap.put(i, integerList.subList(i * limitRounded, toIndex));
}
return integerListMap;
}
结果:
{0 = [1,2,3,4],1 = [5,6,7,8],2 = [9,10]}
答案 0 :(得分:1)
您可以使用groupingBy
进行拆分。
如果需要按元素值
拆分流int split = 4;
Map<Integer, List<Integer>> map2 = integerList.stream().collect(Collectors.groupingBy(i -> (i-1) / split));
System.out.println(map2);
如果需要按位置拆分流
int[] pos = { -1 };
Map<Integer, List<Integer>> map = integerList.stream().peek(e -> pos[0]++).collect(Collectors.groupingBy(e -> pos[0] / split));
System.out.println(map);
输出
{0=[1, 2, 3, 4], 1=[5, 6, 7, 8], 2=[9, 10]}
答案 1 :(得分:0)
我建议你使用这种方法:它从0
迭代到numberOfPartitions
,在每一步创建一个batchLength
元素的子列表(只有最后一步可能少于{{1} }}}并收集batchLength
中的子列表,其中键是当前步骤,值是当前步骤的子列表。
HashMap
按版本分组(非常类似于@Saravana的第二个解决方案):
public static Map<Integer, List<Integer>> partitioningValues(List<Integer> integerList, int numberOfPartitions) {
int size = integerList.size();
BigDecimal limit = BigDecimal.valueOf(size / (double) numberOfPartitions);
int batchLength = limit.setScale(0, BigDecimal.ROUND_UP).intValue();
AtomicInteger step = new AtomicInteger();
return IntStream.range(0, numberOfPartitions)
.boxed()
.collect(
Collectors.toMap(
s -> step.getAndIncrement(),
s -> integerList.subList(s * batchLength, Math.min((s+1)*batchLength, size)))
);
}
答案 2 :(得分:0)
如果您不想改变共享变量以跟踪索引并希望保持流可比较,您仍然可以通过使用替代策略来实现此目的。
分区大小是单个分区中的最大整数数。在所有代码段中,让我们按如下方式定义partitionSize
:
int partitionSize = (list.size() - 1) / partitions + 1;
我们使用简洁的-1 / + 1表示法代替Math.ceil
。
一个简单的天真方法就是找到要分组的索引:
list.stream().collect(groupingBy(i -> list.indexOf(i) / partitionSize));
但是如果你关心性能,你想找到一种更好的方法来处理索引。
直观的方法可能是首先生成所有索引位置,然后迭代它们并收集子列表。这会给你这样的东西,结合List<List<Integer>>
中的所有分区:
int[] indexes = IntStream.iterate(0, i -> i + partitionSize).limit(partitions+1).toArray();
IntStream.range(0, indexes.length - 1)
.mapToObj(i -> list.subList(indexes[i], Math.min(indexes[i + 1], list.size())))
.collect(toList());
如果我们接近列表的末尾,Math.min
用于查找区间的正确结束边界。
但您可以将索引计算和循环结合起来,如下所示:
IntStream.rangeClosed(0, list.size() / partitionSize)
.mapToObj(i -> list.subList(i * partitionSize, Math.min((i+1) * partitionSize, list.size())))
.collect(toList());
注意结果是List<List<Integer>>
,其中每个列表索引都映射在分区的子列表中。
如果你真的想要一张带有按键0,1,2的地图,那么你可以收集到地图:
Map<Integer, List<List<Integer>>> result =
IntStream.rangeClosed(0, list.size() / partitionSize)
.mapToObj(i -> list.subList(i * partitionSize, Math.min((i + 1) * partitionSize, list.size())))
.collect(Collectors.groupingBy(l -> l.get(0) / partitionSize));
或者,如果您不介意使用外部库,例如番石榴已经
Lists.partition(integerList, 3);
示例强>
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); int partitions = 4; int partitionSize = (list.size() - 1) / partitions + 1; //ceil List<List<Integer>> result = IntStream.rangeClosed(0, list.size() / partitionSize) .mapToObj(i -> list.subList(i * partitionSize, Math.min((i+1) * partitionSize, list.size()))) .collect(toList()); System.out.println(result);
结果:[[1,2,3],[4,5,6],[7,8,9],[10]]