[英]How to merge List of Maps of Maps into a Map of Maps?
Could you help me with Java Streams
? 你能帮我解决Java Streams
吗?
As you can see from the title I need to merge List<Map<String, Map<String, Genuineness>>>
into Map<String, Map<String, Genuineness>>
. 从标题中我可以看到,我需要将List<Map<String, Map<String, Genuineness>>>
合并到Map<String, Map<String, Genuineness>>
。
The list is represented as List<Map<String, Map<String, Genuineness>>>
and looks like: 该列表表示为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
}
}
}
]
So, as you can see, duplicate keys could be everywhere. 因此,正如您所看到的,重复的密钥可能无处不在。 My goal is to combine them into Map<String, Map<String, Genuineness>>
by merging Genuineness
. 我的目标是通过合并Genuineness
将它们组合成Map<String, Map<String, Genuineness>>
。 Merge Genuineness
simply means return a new object with summed up values total
, totalGenuine
, and totalDevelopment
. 合并Genuineness
仅仅意味着返回一个新的对象,其总和值为total
, totalGenuine
和totalDevelopment
。
Here is my implementation that fails: 这是我的实现失败:
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()
)
)
)
)
);
It fails with message: 它失败并带有消息:
java.lang.IllegalStateException: Duplicate key {TEST_33_33_APP_1=live.attach.billing.domain.model.billing.Genuineness@951b6fe}
So, seems that in my implementation I've pointed how to combine inner map but didn't make a merging of values of outer map and I don't know how to do it. 所以,似乎在我的实现中我已经指出了如何组合内部地图但没有合并外部地图的值,我不知道该怎么做。
I greatly appreciate your help. 我非常感谢你的帮助。 Thank you in advance! 先感谢您!
UPDATE: Expected output: 更新:预期输出:
{
"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
}
}
}
Honestly, this is a horrible data structure to work with and the maintainers of this code will have a hard time finding out problems that arise. 老实说,这是一个可怕的数据结构,这段代码的维护者很难找到出现的问题。
You should take a step back and consider refactoring the code, any way you can solve the missing part by using the following merge function in the outmost toMap
: 你应该退一步考虑重构代码,你可以通过在最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;
}
Full code: 完整代码:
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;
}
)
);
Though Aomine's suggested solution seems to be correct, you can alternatively improve your code readability and simplify it defining a BinaryOperator<Genuineness>
as : 虽然Aomine建议的解决方案似乎是正确的,但您可以提高代码的可读性并简化它定义BinaryOperator<Genuineness>
方法:
BinaryOperator<Genuineness> remappingGenuineness = (g1, g2) -> new Genuineness(g1.getTotal() + g2.getTotal(),
g1.getTotalGenuine() + g2.getTotalGenuine(),
g1.getTotalDevelopment() + g2.getTotalGenuine()
);
and then further use it as : 然后进一步使用它:
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;
}));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.