如何在 Java 8 中对对象列表进行分页?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29273705/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to paginate a list of objects in Java 8?
提问by adragomir
Given a java.util.List
with n
elements and a desired page size m
, I want to transform it to a map containing n/m+n%m
elements. Each map element shall contain m
elements.
给定java.util.List
withn
元素和所需的页面大小m
,我想将其转换为包含n/m+n%m
元素的地图。每个地图元素都应包含m
元素。
Here's an example with integers:
这是一个整数示例:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// What is the equivalent Java 8 code to create the map below from my list?
Map<Integer, List<Integer>> map = new HashMap<>();
map.put(0, Arrays.asList(1,2,3));
map.put(1, Arrays.asList(4,5,6));
map.put(2, Arrays.asList(7,8,9));
map.put(3, Arrays.asList(10));
Is this possible, using Java 8?
这可能吗,使用 Java 8?
采纳答案by Alexis C.
You could use IntStream.iterate
combined with the toMap
collector and the subList
method on List
(thanks to Duncanfor the simplifications).
您可以IntStream.iterate
结合使用toMap
收集器和subList
方法List
(感谢Duncan的简化)。
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()))));
}
You first calculate the numbers of keys you need in the map. This is given by (list.size() + pageSize - 1) / pageSize
(this will be the limit of the stream).
您首先计算地图中所需的键数。这是由(list.size() + pageSize - 1) / pageSize
(这将是流的限制)给出的。
Then you create a Stream that creates the sequence 0, pageSize, 2* pageSize, ...
.
然后创建一个 Stream 来创建序列0, pageSize, 2* pageSize, ...
。
Now for each value i
you grab the corresponding subList
which will be our value (you need an additional check for the last subList
for not getting out of bounds) for which you map the corresponding key which will be the sequence 0/pageSize, pageSize/pageSize, 2*pageSize/pageSize
that you divide by pageSize
to get the natural sequence 0, 1, 2, ...
.
现在,对于每个值,i
您获取相应subList
的值,这将是我们的值(您需要额外检查最后一个值subList
,以免越界),您映射相应的键,这将是0/pageSize, pageSize/pageSize, 2*pageSize/pageSize
您除以pageSize
获得自然序列的序列0, 1, 2, ...
.
The pipeline can be safely run in parallel (you may need to use the toConcurrentMap
collector instead). As Brian Goetz commented (thanks for reminding me that), iterate
is not worth if you want to parallelize the stream, so here's a version with range
.
管道可以安全地并行运行(您可能需要改用toConcurrentMap
收集器)。正如 Brian Goetz 评论的(感谢您提醒我),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()))));
So as with your example (a list of 10 elements with a page size of 3), you'll get the following sequence:
因此,与您的示例(页面大小为 3 的 10 个元素的列表)一样,您将获得以下序列:
0, 3, 6, 9, 12, 15, ...
that you limit to (10 + 3 - 1) / 3 = 12 / 3 = 4
, which let the sequence 0, 3, 6, 9
. Now each value is mapped to its corresponding sublist:
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>
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(","))
which just collect the elements separated by a comma into a single String.
它只是将逗号分隔的元素收集到一个字符串中。
回答by a better oliver
As noted in the comments this also works if the list is not a natural sequence of integers. You would have to use a generated IntStream
then and refer to the elements in list by index.
如评论中所述,如果列表不是整数的自然序列,这也适用。您必须使用生成的IntStream
then 并按索引引用列表中的元素。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Map<Integer, String> map = IntStream
.range(0, list.size())
.boxed()
.collect(groupingBy(
i -> i / 3, //no longer i-1 because we start with 0
mapping(i -> list.get((int) i).toString(), joining(","))
));
//result: {0="1,2,3", 1="4,5,6", 2="7,8,9", 3="10"}
We start with an IntStream
representing the indices of the list.
我们从IntStream
表示列表索引的开始。
groupingBy
groups the elements by some classifier. In your case it groups x elements per page.
groupingBy
通过某个分类器对元素进行分组。在您的情况下,它将每页分组 x 个元素。
mapping
applies a mapping function to the elements and collects them afterwards. The mapping is necessary because joining
only accepts CharSequence
. joining
itself joins the elements by using an arbitrary delimiter.
mapping
对元素应用映射函数并在之后收集它们。映射是必要的,因为joining
只接受CharSequence
. joining
本身通过使用任意分隔符连接元素。
回答by u290629
Simple solution using Guava: com.google.common.collect.Lists#partition:
使用 Guava 的简单解决方案:com.google.common.collect.Lists#partition:
List<List<Integer>> partition = Lists.partition(list, 3); //<- here
Map map = IntStream.range(0, partition.size()).boxed().collect(Collectors.toMap(
Function.identity(),
i -> partition.get(i)));