我收到了一个名为 listResult
的json响应,格式为List<Map<String, Object>>
,每个Map
有两个重要条目,如下所示:
{
key1:category,
key2:num
}
然后,List<Map<String, Object>>
将显示如下:
[
{
key1:c1,
key2:1
},{
key1:c2,
key2:2
},{
key1:c1,
key2:4
}
]
我想要得到的是以下内容:
{
c1:5, // 1 + 4 according to c1
c2:2
}
使用传统方式,代码如下:
Map<String, BigDecimal> topCount = new HashMap<String, BigDecimal>();
for (Map<String, Object> topDataMap : listResult) {
BigDecimal count = topCount.getOrDefault(topDataMap.get(ARTICLE_ITEM_CODE_KEY), BigDecimal.ZERO);
topCount.put((String) topDataMap.get(ARTICLE_ITEM_CODE_KEY),
count.add((BigDecimal) topDataMap.get(VALUE_KEY)));
}
问题是:如何使用java8实现此目标?
======================
我忘记了我还需要在同一数据流中按值对结果图进行排序。
我可以用两次stream()
来做到这一点,但是我想知道是否只有一次stream()
会更简单?
答案 0 :(得分:0)
我想出了一个解决方案。
关键是您应该map
首先,将Map<String, Object>
转换为具有原始地图值的目标地图Map<String, BigDecimal>
。
Map<String, Double> topCount = queryResult.getData().getResult().stream()
.map(m -> new HashMap<String, Double>() {
{
put((String) m.get(ARTICLE_ITEM_CODE_KEY), ((BigDecimal) m.get(VALUE_KEY)).doubleValue());
}
}).flatMap(m -> m.entrySet().stream())
.collect(groupingBy(Map.Entry::getKey, summingDouble(Map.Entry::getValue)))
.entrySet().stream().sorted(Map.Entry.<String, Double>comparingByValue().reversed())
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
==========================
感谢@Andreas。 此外,我还需要对结果图进行排序。基于@Andreas答案,我使用以下代码进行操作:
Map<String, BigDecimal> topCount = queryResult.getData().getResult().stream()
.collect(toMap(
m -> (String) m.get(ARTICLE_ITEM_CODE_KEY),
m -> (BigDecimal) m.get(VALUE_KEY),
BigDecimal::add))
.entrySet().stream().sorted(Map.Entry.<String, BigDecimal>comparingByValue().reversed())
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
但是它两次使用stream()
。我不知道如何只用一个stream()
答案 1 :(得分:0)
要转换
[{key1=c1, key2=1}, {key1=c2, key2=1}, {key1=c1, key2=4}]
进入
{c1=5, c2=1}
使用Java 8流,您可以
Map<String, BigDecimal> topCount = listResult.stream().collect(Collectors.toMap(
m -> (String) m.get("key1"),
m -> (BigDecimal) m.get("key2"),
BigDecimal::add
));
完整代码
List<Map<String, Object>> listResult = List.of(
Map.of("key1", "c1", "key2", BigDecimal.valueOf(1)),
Map.of("key1", "c2", "key2", BigDecimal.valueOf(1)),
Map.of("key1", "c1", "key2", BigDecimal.valueOf(4))
);
Map<String, BigDecimal> topCount = listResult.stream().collect(Collectors.toMap(
m -> (String) m.get("key1"),
m -> (BigDecimal) m.get("key2"),
BigDecimal::add
));
System.out.println(topCount);
输出
{c1=5, c2=1}
更新来自comment:
此外,如果我想按值desc排序结果映射,我如何在相同的流中实现它?
Map
不能自然地按值排序,但是您可以对数据进行排序,然后构建一个新的LinkedHashMap
,以保留插入顺序。
首先,您必须如上所述构建Map
,以获取要排序的值,然后对地图条目进行排序并构建所需的地图:
Map<String, BigDecimal> topCount = listResult.stream().collect(Collectors.toMap(
m -> (String) m.get("key1"),
m -> (BigDecimal) m.get("key2"),
BigDecimal::add
)).entrySet().stream()
.sorted(Comparator.<Entry<String, BigDecimal>, BigDecimal>comparing(Entry::getValue).reversed())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue,
(a,b) -> { throw new AssertionError(); },
LinkedHashMap::new));