简体   繁体   English

Java 8列表 <Map<String, Object> &gt;列表 <Map<String, Object> &gt;按键分组并按值计数

[英]Java 8 List<Map<String, Object>> to List<Map<String, Object>> group by key and count by value

I have the following list of maps 我有以下地图列表

List<Map<String, Object>> listBeforeGroup = new ArrayList<Map<String, Object>>();

    Map<String, Object> m1 = new HashMap<String, Object>();
    m1.put("company", "LG");
    m1.put("billType", "A");
    m1.put("billPeriod", "09-2018");

    Map<String, Object> m2 = new HashMap<String, Object>();
    m2.put("company", "LG");
    m2.put("billType", "A");
    m2.put("billPeriod", "09-2018");

    Map<String, Object> m3 = new HashMap<String, Object>();
    m3.put("company", "LG");
    m3.put("billType", "A");
    m3.put("billPeriod", "09-2018");

    Map<String, Object> m4 = new HashMap<String, Object>();
    m4.put("company", "LG");
    m4.put("billType", "B");
    m4.put("billPeriod", "01-2019");

    Map<String, Object> m5 = new HashMap<String, Object>();
    m5.put("company", "LG");
    m5.put("billType", "B");
    m5.put("billPeriod", "01-2019");

    Map<String, Object> m6 = new HashMap<String, Object>();
    m6.put("company", "Samsung");
    m6.put("billType", "A");
    m6.put("billPeriod", "10-2018");

    Map<String, Object> m7 = new HashMap<String, Object>();
    m7.put("company", "Samsung");
    m7.put("billType", "A");
    m7.put("billPeriod", "10-2018");

    Map<String, Object> m8 = new HashMap<String, Object>();
    m8.put("company", "Samsung");
    m8.put("billType", "B");
    m8.put("billPeriod", "11-2018");

    listBeforeGroup.add(m1);listBeforeGroup.add(m2);
    listBeforeGroup.add(m3);listBeforeGroup.add(m4);
    listBeforeGroup.add(m5);listBeforeGroup.add(m6);

How do I get this output? 我如何获得此输出?

    //Desired Output - List<Map<String, Object>>
    //{company=LG, billType=A, billPeriod=09-2018, count=3}
    //{company=LG, billType=B, billPeriod=01-2019, count=2}
    //{company=Samsung, billType=A, billPeriod=10-2018, count=2}
    //{company=Samsung, billType=B, billPeriod=11-2018, count=1}

I tried this, using java 8 streams, but I can't get the desired output 我试过这个,使用java 8流,但我无法获得所需的输出

List<Map<String, Object>> listAfterGroup = listBeforeGroup.stream().map(m -> m.entrySet().stream().collect(Collectors.toMap(p -> p.getKey(), p - >  p.getValue()))).collect(Collectors.toList());

And tried this, btw this solution gives a map but I don't want this 并试过这个,顺便说一下这个解决方案给出了一张地图,但我不想要这个

Map<Object, Long> listAfterGroup = listBeforeGroup.stream().flatMap(m -> m.entrySet().stream()).collect(Collectors.groupingBy(Map.Entry::getKey,Collectors.counting()));

I want to group the maps by the key "billPeriod" for example, and count items by the values, then generate a new list of maps. 我想通过键“billPeriod”对地图进行分组,然后按值计算项目,然后生成新的地图列表。

You can create a class Company and then subsequent operations become much simpler. 您可以创建一个类Company ,然后后续操作变得更加简单。

class Company {
    String company;
    String billType;
    String billPeriod;

    public Company(String company, String billType, String billPeriod) {
        this.company = company;
        this.billType = billType;
        this.billPeriod = billPeriod;
    }

    // getters, setters, toString, etc
}

Initialize the list : 初始化列表:

List<Company> list = new ArrayList<>();
list.add(new Company("LG", "A", "09-2018"));
list.add(new Company("LG", "A", "09-2018"));
list.add(new Company("LG", "A", "09-2018"));
list.add(new Company("LG", "B", "01-2019"));
list.add(new Company("LG", "B", "01-2019"));
list.add(new Company("Samsung", "A", "10-2018"));
list.add(new Company("Samsung", "A", "10-2018"));
list.add(new Company("Samsung", "B", "11-2018"));

Now for an example, you can group by company name : 现在举个例子,你可以按公司名称分组:

Map<String, Long> map = list.stream().collect(
        Collectors.groupingBy(Company::getCompany, 
                              Collectors.mapping((Company c) -> c, Collectors.counting())));

Now it becomes much easier to perform other operations as you desire. 现在,按照您的意愿执行其他操作变得更加容易。 Also, here instead of creating 8 maps you end up dealing with just 1 list . 此外,这里不是创建8个地图 ,而是仅处理1个列表

It's really difficult to grouping and counting a map because your map data will be changed after you increase your counter value. 分组和计算地图非常困难,因为在增加计数器值后,地图数据将会更改。 Therefore, you must save the original data of the map, and save your counter value to the another map. 因此,您必须保存地图的原始数据,并将计数器值保存到另一个地图。 Join 2 maps after your counting process is complete. 计数过程完成后,加入2张地图。

Map<Map<String, Object>, Long> counterData = listBeforeGroup.stream().collect(Collectors.groupingBy(m -> m, Collectors.counting()));

List<Map<String, Object>> listAfterGroup = new ArrayList<>();
for (Map<String, Object> m : counterData.keySet()) {
    Map<String, Object> newMap = new HashMap<>(m);
    newMap.put("count", counterData.get(m));
    listAfterGroup.add(newMap);
}

Update Java 8 approach, not easy to debug 更新Java 8方法,不易调试

List<Map<String, Object>> listAfterGroup = listBeforeGroup.stream().collect(Collectors.groupingBy(m -> m, Collectors.counting())).entrySet().stream().map(e -> {
    Map<String, Object> newMap = e.getKey();
    newMap.put("count", e.getValue());
    return newMap;
}).collect(Collectors.toList());

My approach with java 8: 我使用java 8的方法:

    Function<Map<String, Object>, String> createHashKey = map ->
                     map.values().stream()
                    .map(val -> String.valueOf(val))
                    .collect(Collectors.joining());

    BinaryOperator<Map<String, Object>> mergeDuplicate = (map1, map2) -> {
        int incrementedCount = (int)map1.get("count") + 1;
        map1.put("count", incrementedCount);
        return map1;
    };

    List<Map<String, Object>> listAfterGroup = listBeforeGroup.stream()
            .collect(Collectors.toMap(createHashKey, el -> {
                        el.put("count", 1);
                        return el;
            },mergeDuplicate))
          .values().stream()
          .collect(toList());

Maybe not the most succinct solution but I think quite readable and easy to follow the logic of the code. 也许不是最简洁的解决方案,但我认为很容易理解代码的逻辑。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何分组清单 <Map<String,Object> &gt;到地图 <String,List<Map<String,Object> &gt;在Java8中 - How to group List<Map<String,Object>> to Map<String,List<Map<String,Object>> in Java8 列表<map<string, object> &gt; 列出<map<string, object> &gt; 用空值按键分组</map<string,></map<string,> - List<Map<String, Object>> to List<Map<String, Object>> group by key with nulls 比较列表<map<string, string> &gt; 到列表<map<string, object> &gt; Java </map<string,></map<string,> - Comparing a List<Map<String, String>> to a List<Map<String, Object>> Java 在 java 列表中转换<pojo>至 Map <string, list<object> &gt; 其中键是字段名称,值是按字段列出的值列表</string,></pojo> - Convert in java List<POJO> to Map<String, List<Object>> where the key is a field name and value is a list of values by field 如何迭代列表<Map<String, Object> &gt; 并在java中的另一个哈希映射中动态添加键和值 - How to iterate List<Map<String, Object>> and add the key and value dynamically in another hash map in java 转换列表<String>到地图<String, List<String> &gt; 以列表值为映射键,以空列表为映射值 java 8 - Convert List<String> to Map<String, List<String>> with list value as map key and map value with empty list java 8 Java 8流 - 查找Map的最大计数值 <String, List<Object> &gt; - Java 8 stream - Find max count values for Map<String, List<Object>> 处理 Map 列表<String,List<Object> &gt; 在 Java 8 中 - Processing a list of Map<String,List<Object>> in java 8 地图的分组和聚合列表<String, Object> - Group and Aggregate List of Map<String, Object> 如何过滤和检查列表中特定键和值是否存在列表<map<string, object> > 在 java </map<string,> - How to filter and check if specific key and value exists list in List<Map<String, Object>> in java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM