您能帮我Java Streams
吗?
从标题中可以看到,我需要将List<Map<String, Map<String, Genuineness>>>
合并到Map<String, Map<String, Genuineness>>
中。
该列表表示为List<Map<String, Map<String, Genuineness>>>
,看起来像:
[
{
"USER_1":{
"APP_1":{
"total":1,
"totalGenuine":1,
"totalDevelopment":1
}
},
"USER_2":{
"APP_1":{
"total":1,
"totalGenuine":1,
"totalDevelopment":1
},
"APP_2":{
"total":2,
"totalGenuine":2,
"totalDevelopment":2
}
}
},
{
"USER_1":{
"APP_1":{
"total":1,
"totalGenuine":1,
"totalDevelopment":1
}
},
"USER_2":{
"APP_1":{
"total":1,
"totalGenuine":1,
"totalDevelopment":1
},
"APP_2":{
"total":2,
"totalGenuine":2,
"totalDevelopment":2
}
}
}
]
因此,如您所见,重复的键可能无处不在。
我的目标是通过合并Map<String, Map<String, Genuineness>>
将它们合并到Genuineness
中。合并Genuineness
只是意味着返回一个具有总计值total
,totalGenuine
和totalDevelopment
的新对象。
这是我的实施失败的地方:
final Map<String, Map<String, Genuineness>> map = taskHandles.stream().map(this::mapTaskHandle)
.flatMap(m -> m.entrySet().stream()).collect(
Collectors.toMap(Map.Entry::getKey, e -> e.getValue().entrySet().stream()
.collect(
Collectors.toMap(Map.Entry::getKey,
g -> new Genuineness(g.getValue().getTotal(), g.getValue().getTotalGenuine(), g.getValue().getTotalDevelopment()),
(g1, g2) -> new Genuineness(g1.getTotal() + g2.getTotal(),
g1.getTotalGenuine() + g2.getTotalGenuine(),
g1.getTotalDevelopment() + g2.getTotalGenuine()
)
)
)
)
);
失败,并显示以下消息:
java.lang.IllegalStateException: Duplicate key {TEST_33_33_APP_1=live.attach.billing.domain.model.billing.Genuineness@951b6fe}
因此,似乎在我的实现中,我指出了如何组合内部地图,但没有合并外部地图的值,而且我也不知道该怎么做。
非常感谢您的帮助。预先谢谢你!
更新: 预期输出:
{
"USER_1":{
"APP_1":{
"total":2,
"totalGenuine":2,
"totalDevelopment":2
}
},
"USER_2":{
"APP_1":{
"total":2,
"totalGenuine":2,
"totalDevelopment":2
},
"APP_2":{
"total":4,
"totalGenuine":4,
"totalDevelopment":4
}
}
}
答案 0 :(得分:4)
老实说,这是一个可怕的数据结构,该代码的维护者将很难发现出现的问题。
您应该退后一步并考虑重构代码,以任何方式可以通过在最外面的toMap
中使用以下合并函数来解决缺少的部分:
(l, r) -> {
r.forEach((k, v) -> l.merge(k, v,
(bi, bii) -> new Genuineness(bi.getTotal() + bii.getTotal(),
bi.getTotalGenuine() + bii.getTotalGenuine(),
bi.getTotalDevelopment() + bii.getTotalGenuine())));
return l;
}
完整代码:
taskHandles.stream().map(this::mapTaskHandle)
.flatMap(m -> m.entrySet().stream()).collect(
Collectors.toMap(Map.Entry::getKey, e -> e.getValue().entrySet().stream()
.collect(
Collectors.toMap(Map.Entry::getKey,
g -> new Genuineness(g.getValue().getTotal(), g.getValue().getTotalGenuine(), g.getValue().getTotalDevelopment()),
(g1, g2) -> new Genuineness(g1.getTotal() + g2.getTotal(),
g1.getTotalGenuine() + g2.getTotalGenuine(),
g1.getTotalDevelopment() + g2.getTotalGenuine()
)
)
),(l, r) -> {
r.forEach((k, v) -> l.merge(k, v,
(bi, bii) -> new Genuineness(bi.getTotal() + bii.getTotal(),
bi.getTotalGenuine() + bii.getTotalGenuine(),
bi.getTotalDevelopment() + bii.getTotalGenuine())));
return l;
}
)
);
答案 1 :(得分:3)
尽管Aomine's suggested solution似乎是正确的,但是您也可以提高代码的可读性并简化将BinaryOperator<Genuineness>
定义为的代码:
BinaryOperator<Genuineness> remappingGenuineness = (g1, g2) -> new Genuineness(g1.getTotal() + g2.getTotal(),
g1.getTotalGenuine() + g2.getTotalGenuine(),
g1.getTotalDevelopment() + g2.getTotalGenuine()
);
,然后将其用作:
final Map<String, Map<String, Genuineness>> map = taskHandles.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey,
e -> e.getValue().entrySet().stream().collect(
Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, remappingGenuineness)),
(a, b) -> {
a.forEach((k, v) -> b.merge(k, v, remappingGenuineness));
return b;
}));