[英]How to merge List of Maps of Maps into a Map of Maps?
你能幫我解決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
}
}
}
]
因此,正如您所看到的,重復的密鑰可能無處不在。 我的目標是通過合並Genuineness
將它們組合成Map<String, Map<String, 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
}
}
}
老實說,這是一個可怕的數據結構,這段代碼的維護者很難找到出現的問題。
你應該退一步考慮重構代碼,你可以通過在最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;
}
)
);
雖然Aomine建議的解決方案似乎是正確的,但您可以提高代碼的可讀性並簡化它定義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;
}));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.