您可以结合收集器和方法使用(感谢Duncan的简化)。IntStream.iterate
toMap
subList
List
import static java.util.stream.Collectors.toMap;
import static java.lang.Math.min;
...
static Map<Integer, List<Integer>> partition(List<Integer> list, int pageSize) {
return IntStream.iterate(0, i -> i + pageSize)
.limit((list.size() + pageSize - 1) / pageSize)
.boxed()
.collect(toMap(i -> i / pageSize,
i -> list.subList(i, min(i + pageSize, list.size()))));
}
首先计算地图中所需的键数。这是由(这将是流的限制)给出的。(list.size() + pageSize - 1) / pageSize
然后,创建一个创建序列的流。0, pageSize, 2* pageSize, ...
现在,对于每个值,您获取相应的值,这将是我们的值(您需要对最后一个值进行额外检查以未越界),为此您可以映射相应的键,该键将是您除以得到自然序列的序列。i
subList
subList
0/pageSize, pageSize/pageSize, 2*pageSize/pageSize
pageSize
0, 1, 2, ...
管道可以安全地并行运行(您可能需要改用收集器)。正如 Brian Goetz 所评论的那样(感谢您提醒我),如果您想并行化流,则不值得,因此这里有一个带有 .toConcurrentMap
iterate
range
return IntStream.range(0, (list.size() + pageSize - 1) / pageSize)
.boxed()
.collect(toMap(i -> i ,
i -> list.subList(i * pageSize, min(pageSize * (i + 1), list.size()))));
因此,与您的示例(页面大小为 3 的 10 个元素的列表)一样,您将获得以下序列:
0, 3, 6, 9, 12, 15, ...
,则限制为 ,这让序列 .现在每个值都映射到其相应的子列表:(10 + 3 - 1) / 3 = 12 / 3 = 4
0, 3, 6, 9
0 / pageSize = 0 -> list.subList(0, min(0 + pageSize, 10)) = list.subList(0, 3);
3 / pageSize = 1 -> list.subList(3, min(3 + pageSize, 10)) = list.subList(3, 6);
6 / pageSize = 2 -> list.subList(6, min(6 + pageSize, 10)) = list.subList(6, 9);
9 / pageSize = 3 -> list.subList(9, min(9 + pageSize, 10)) = list.subList(6, 10);
^
|
this is the edge-case for the last sublist to
not be out of bounds
如果你真的想要一个,你可以用
Map<Integer, String>
import static java.util.stream.Collectors.joining;
...
i -> list.subList(i, min(i + pageSize, list.size()))
.stream()
.map(Object::toString)
.collect(joining(","))
它只是将逗号分隔的元素收集到单个字符串中。