Java 8 groupingby到包含列表

时间:2018-01-24 20:51:40

标签: java java-8 java-stream

我有以下数据:

List<Map<String, Object>> products = new ArrayList<>();

Map<String, Object> product1 = new HashMap<>();
product1.put("Id", 1);
product1.put("number", "123");
product1.put("location", "ny");

Map<String, Object> product2 = new HashMap<>();
product2.put("Id", 1);
product2.put("number", "456");
product2.put("location", "ny");

Map<String, Object> product3 = new HashMap<>();
product3.put("Id", 2);
product3.put("number", "789");
product3.put("location", "ny");

products.add(product1);
products.add(product2);
products.add(product3);

我尝试在产品列表上流式传输,按ID分组,每个ID都有一个数字列表,同时返回包含三个键的地图:Id,数字列表和位置。< / p>

所以我的输出是:

List<Map<String, Object>>> groupedProducts
map[0]
    {id:1, number[123,456], location:ny}
map[1]
    {id:2, number[789], location:ny}

我试过了:

Map<String, List<Object>> groupedProducts = products.stream()
      .flatMap(m -> m.entrySet().stream())
      .collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toList())));

打印:

{number=[123, 456, 789], location=[ny, ny, ny], Id=[1, 1, 2]}

我意识到Map<String, List<Object>>不正确,但它是我能够实现的最佳流程。任何反馈都表示赞赏。

1 个答案:

答案 0 :(得分:2)

在您的情况下,Id键与Collectors.collectingAndThen(downstream, finisher)分组可以解决问题。请考虑以下示例:

Collection<Map<String, Object>> finalMaps = products.stream()
        .collect(groupingBy(it -> it.get("Id"), Collectors.collectingAndThen(
                Collectors.toList(),
                maps -> (Map<String, Object>) maps.stream()
                        .reduce(new HashMap<>(), (result, map) -> {
                            final List<Object> numbers = (List<Object>) result.getOrDefault("number", new ArrayList<>());

                            result.put("Id", map.getOrDefault("Id", result.getOrDefault("Id", null)));
                            result.put("location", map.getOrDefault("location", result.getOrDefault("location", null)));

                            if (map.containsKey("number")) {
                                numbers.add(map.get("number"));
                            }
                            result.put("number", numbers);

                            return result;
                        }))
                )
        )
        .values();

System.out.println(finalMaps);

在第一步中,您将具有相同Id值的所有地图分组到List<Map<String,Object>>(这是Collectors.toList()传递给.collectingAndThen()的地图。创建该列表&#34;终结者&#34;调用函数 - 在这种情况下,我们使用Stream.reduce()操作将地图列表转换为单个地图 - 我们从空HashMap<String,Object>开始,我们迭代地图,在迭代中从当前地图获取值并设置值根据您的规范(&#34; Id&#34;和&#34;位置&#34;被覆盖,&#34;数字&#34;保留值列表)。

输出

[{number=[123, 456], location=ny, Id=1}, {number=[789], location=ny, Id=2}]

为了使代码更简单,您可以将传递给BiOperator的{​​{1}}提取到方法并改为使用方法引用。这个函数定义了将两个映射组合成单个映射的意义,因此它是整个映射的核心逻辑。