如何在保留订单的同时将List <P>中的元素分组到Map <K,List <V >>?

Jam*_*phy 18 java linkedhashmap java-8 java-stream collectors

我有一个从Google Places API中获取的Google PlaceSummary对象列表.我想通过他们的Google商家信息ID收集和分组,但也保留元素的顺序.我认为会起作用的是:

Map<String, List<PlaceSummary>> placesGroupedByPlaceId =
            places.stream()
                  .collect(Collectors.groupingBy(
                          PlaceSummary::getPlaceId,
                          LinkedHashMap::new,
                          Collectors.mapping(PlaceSummary::getPlaceId, toList())
                  ));
Run Code Online (Sandbox Code Playgroud)

但它甚至不会编译.它看起来应该根据收集器上Java API文档.

以前我有这个代码:

    Map<String, List<PlaceSummary>> placesGroupedByPlaceId = places.stream()
            .collect(Collectors.groupingBy(PlaceSummary::getPlaceId));
Run Code Online (Sandbox Code Playgroud)

但是.collect(),Streams API上的标准不保留后续元素的顺序HashMap(显然因为HashMaps是无序的).我希望输出为a,LinkedHashMap以便Map按每个桶的插入顺序排序.

但是,我建议的解决方案不能编译.首先,它不承认PlaceSummary::getPlaceId它,因为它说它不是一个功能 - 即使我知道它是.其次,它说我不能转换LinkedHashMap<Object, Object>成M. M应该是一个通用的集合,所以它应该被接受.

如何将List转换为LinkedHashMap使用Java Stream API?有简洁的方法吗?如果它太难理解我可能只是采用旧学前Java 8方法.

我注意到在将List转换为LinkedHashMap时还有另一个Stack Overflow答案,但是这没有我想要的解决方案,因为我需要收集'this'我正在迭代的对象.

Tun*_*aki 19

你真的很接近你想要的:

Map<String, List<PlaceSummary>> placesGroupedByPlaceId =
            places.stream()
                  .collect(Collectors.groupingBy(
                          PlaceSummary::getPlaceId,
                          LinkedHashMap::new,
                          Collectors.mapping(Function.identity(), Collectors.toList())
                  ));
Run Code Online (Sandbox Code Playgroud)

在该Collectors.mapping方法中,您需要提供PlaceSummary实例而不是地点ID.在上面的代码中,我使用了Function.identity():这个收集器用于构建值,因此我们需要累积位置本身(而不是它们的ID).

请注意,可以直接写入Collectors.toList()而不是Collectors.mapping(Function.identity(), Collectors.toList()).

到目前为止你的代码没有编译,因为它实际上创建了一个Map<String, List<String>>:你正在为每个ID累积ID(这很奇怪).


您可以将其写为通用方法:

private static <K, V> Map<K, List<V>> groupByOrdered(List<V> list, Function<V, K> keyFunction) {
    return list.stream()
                .collect(Collectors.groupingBy(
                    keyFunction,
                    LinkedHashMap::new,
                    Collectors.toList()
                ));
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

Map<String, List<PlaceSummary>> placesGroupedById = groupByOrdered(places, PlaceSummary::getPlaceId);
Run Code Online (Sandbox Code Playgroud)