问题描述
我正在尝试处理具有以下格式的列表:
List<Map<String,Map<String,Item>>
至Map<String,List<Item>>
,其中Item
是包含两个属性的对象。
因此输入:
[
<"A1",<"B1",Item_1>>,<"A1",Item_2>>,<"B2",Item_3>>,<"A2",Item_4>>,Item_5>>,Item_6>>
]
输出应为:
"A1" {
<"B1",[Item_1,Item_2]>
<"B2",[Item_3]>
}
"A2" {
<"B1",[Item_4]>
<"B2",[Item_5,Item_6]>
}
我尝试使用:
list.stream()
.flatMap(it -> it.entrySet().stream())
.collect(groupingBy(Map.Entry::getKey,Collectors.mapping(Map.Entry::getValues,Collectors.toList())));
但结果不是期望的结果,它返回Map<String,List<Map<String,Item>>>
{
"A1": [
<"B1",Item_1>,Item_2>,Item_3>
]
"A2": [
<"B1",Item_4>,Item_5>,Item_6>
]
}
您能建议我如何同时按B_键进行分组吗?谢谢!
解决方法
如果可以将条目展平为三元组数据结构,则可以使用B_
键进行分组。尽管这对于映射条目是可行的,但在实现方面却相当混乱。更好的选择是创建自己的数据结构以临时保存这三个扁平化的属性。
这是我将在解决方案中进一步使用的类似代码之一。
@Getter
@AllArgsConstructor
static class Holder {
String a;
String b;
Item c;
}
现在,另一个重要的点是确保平整结构,直到代码中共享的最里面的条目而不只是最外面的Map
为止。这将需要使用嵌套的flatMap
。
list.stream()
.flatMap(out -> out.entrySet().stream()
.flatMap(e -> e.getValue().entrySet().stream()
.map(in -> new Holder(e.getKey(),in.getKey(),in.getValue()))))
到最后,您将拥有一个Stream<Holder>
,可以将其进一步分组两次并映射以推断预期的结果。这是针对此问题的完整解决方案:
list.stream()
.flatMap(out -> out.entrySet().stream()
.flatMap(e -> e.getValue().entrySet().stream()
.map(in -> new Holder(e.getKey(),in.getValue()))))
.collect(Collectors.groupingBy(Holder::getA,Collectors.groupingBy(Holder::getB,Collectors.mapping(Holder::getC,Collectors.toList()))));