给定具有java.util.List元素的n和所需的页面大小m,我想将其转换为包含n/m+n%m元素的 map 。每个 map 元素应包含m元素。

这是一个整数示例:

    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));

使用Java 8可以吗?

最佳答案

您可以将IntStream.iteratetoMap收集器和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()))));
}

首先,您需要计算 map 中所需的键数。这由(list.size() + pageSize - 1) / pageSize给出(这将是流的限制)。

然后,创建一个流,该流创建序列0, pageSize, 2* pageSize, ...

现在,对于每个值i,您都将获取对应的subList,它将作为我们的值(您需要对最后的subList进行额外检查,以确保不超出范围),为此您映射了对应的键,该键将是被0/pageSize, pageSize/pageSize, 2*pageSize/pageSize除以的序列pageSize得到自然序列0, 1, 2, ...

管道可以安全地并行运行(您可能需要使用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()))));

因此,与您的示例(页面大小为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>,则可以将value mapper函数替换为
import static java.util.stream.Collectors.joining;

...

i -> list.subList(i, min(i + pageSize, list.size()))
         .stream()
         .map(Object::toString)
         .collect(joining(","))

只是将用逗号分隔的元素收集到单个String中。

10-06 16:19
查看更多