简体   繁体   中英

How make multiple aggregation on list of HashMaps with java 8

I have an issue with java 8 implementation regarding multiple aggregation of HashMap list , (preferred with "reduce" function , but not must)

I need to make multiple aggregation by key name - "service" with split("_")[0] as in Json below:

Suppose my data structure :

 List<Map<String, Object>> payments = new ArrayList<>();
  for(int i=0 ; ....i++){
      Map<String, String> map = new HashMap<>();
      map.put("service","IMAP_"+i);
      map.put("storageValue",<some value>)
      ....
      payments.add(map);
  }

The Json:

{
  "payments": [
    {
      "service": "IMAP_1",
      "storageValue": 10,
      "users": "10"
    },
    {
      "service": IMAP_2,
      "storageValue": 20,
      "users": "1"
    },
    {
      "storageValue": 200,
      "service": "Office 365 Exchange_1",
      "users": "15"
    },
    {
      "storageValue": 200,
      "service": "Office 365 Exchange_2",
      "users": "10"
    },
    {
      "storageValue": 50,
      "service": "SalesForce_1",
      "users": "100"
    }
  ]
}

The result should be :

{
      "payments": [
        {
          "service": "IMAP",
          "storageValue": 30,
          "users": "11"
        },
        {
          "storageValue": 400,
          "service": "Office 365 Exchange",
          "users": "25"
        },
        {
          "storageValue": 50,
          "service": "SalesForce",
          "users": "100"
        }
      ]
    }

should be something..

payments.stream().forEach(paymet -> {
                paymet.entrySet().stream().map(....?...).reduce()...
            );

Here's an incomplete suggestion that combines Collectors.groupingBy with Collectors.reducing .

Map<String,Optional<Map<String,Object>>> result = 
    payments.stream ().collect(Collectors.groupingBy (map -> map.get ("service").split ("_")[0],
                               Collectors.reducing ((m1,m2)-> {
                                   Map<String,String> m = new HashMap<>();
                                   m.put("service",m1.get("service")); // you may have to remove the _1 suffix
                                   m.put("storageValue",(Integer)m1.get("storageValue")+(Integer)m2.get("storageValue"));
                                   m.put("users",(Integer)m1.get("users")+(Integer)m2.get("users"));
                                   return m;
                               })));

Note that since your Map s contain String values, it's a bit inconvenient to add the values of these Map as if they are numbers. You'll have to do some conversions from String to int and vice versa.

It might be helpful to convert each Map into an instance of some class having storage, users and storageValue properties. Then you can have a method that combines two such instances.

Try this one. it isn't elegance :).

first change service key's value to the new value

 payments.stream()
            .forEach(item -> item.put("service", item.get("service").split("_")[0]));

then

HashMap<String, HashMap> mapOfMaps = payments.stream()
            .collect(Collectors.toMap(hashMap -> hashMap.get("service"),
                    hashMap -> (HashMap) hashMap,
                    YOURCLASS::merge, HashMap::new));
List<HashMap> result = new ArrayList<>(mapOfMaps.values());

and define a method to merge two maps like following:

private static HashMap<String, String> merge(HashMap<String, String> map1, HashMap<String, String> map2) {
    if (map1.get("service").equals(map2.get("service"))) {
        Long storageValue = Long.valueOf(map1.get("storageValue")) + Long.valueOf(map2.get("storageValue"));
        map1.put("storageValue", storageValue.toString());
        Long users = Long.valueOf(map1.get("users")) + Long.valueOf(map2.get("users"));
        map1.put("users", users.toString());
    }
    return map1;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM