列出<map <string,object =“” >>组,并将其简化为Map <v1,v2 =“”>,

时间:2018-08-23 02:58:32

标签: java java-8

我收到了一个名为 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()会更简单?

2 个答案:

答案 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));