Java 8 Streams - 分组为单值

时间:2017-03-31 10:14:33

标签: java java-8 java-stream

我目前正在使用List<Map<String, Object>>我正尝试在地图中的各个键之间进行分组。 这似乎可以很好地使用Java 8 Stream s:

Map<Object, Map<Object, List<Map<String, Object>>>> collect =
   list
   .stream()
   .collect(Collectors.groupingBy(
       item -> item.get("key1"),
       Collectors.groupingBy(item -> item.get("key2"))
   ));

正如预期的那样,这给了我一个Map<Object, Map<Object, List<Map<String, Object>>>>,在可能的分组结果大于1的情况下效果很好。

我有各种例子,例如,正在进行的分组将始终导致最低级别列表中的单个项目。

行列表

{
  [reference="PersonX", firstname="Person", dob="test", lastname="x"],
  [reference="JohnBartlett", firstname="John", dob="test", lastname="Bartlett"]
}

以引用方式分组

目前 - 已分组为包含1 Map<String,Object>

的列表
[PersonX, { [reference="PersonX", firstname="Person", dob="test", lastname="x"]}],
[JohnBartlett, { [reference="JohnBartlett", firstname="John", dob="test", lastname="Bartlett"]}]

偏好 - 仅列出一个Map<String,Object>

[PersonX, [reference="PersonX", firstname="Person", dob="test", lastname="x"]],
[JohnBartlett, [reference="JohnBartlett", firstname="John", dob="test", lastname="Bartlett"]]

在流中是否有一种方法可以强制这些实例的输出为Map<Object, Map<Object, Map<String, Object>>> - 所以只有一个Map<String,Object>而不是List个?{/ p>

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:10)

如果我理解正确,那么对于确定有一个项目的情况,您应该只替换:

 .collect(Collectors.groupingBy(
   item -> item.get("key1"),
   Collectors.toMap(item -> item.get("key2"), Function.identity())
 ));

您甚至可以提供第三个参数作为BinaryOperator来合并相同的条目(如果您需要)

答案 1 :(得分:2)

Collectors.toMap()完全可以满足您的需求。

Map<Object, Map<String, Object>> collect = maps.stream()
        .collect(Collectors.toMap(p -> p.get("reference"), Function.identity()));

输出:

{
  PersonX={firstname=Person, reference=PersonX, lastname=x, dob=test},
  JohnBartlett={firstname=John, reference=JohnBartlett, lastname=Bartlett, dob=test}
}

如果您有重复的键,这将抛出一个IllegalStateException,这可能恰好是您在从未希望数据中存在重复记录时想要的键:

Exception in thread "main" java.lang.IllegalStateException: Duplicate key JohnBartlett (attempted merging values {dob=test, lastname=Bartlett, reference=JohnBartlett, firstname=John} and {dob=test 2, lastname=Bartlett, reference=JohnBartlett, firstname=John})
    at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:133)
    at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:180)
    at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
    at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(AbstractList.java:720)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
    at so.UniqueKeyStreamExample.main(UniqueKeyStreamExample.java:22)