How make multiple aggregation on list of HashMaps with java 8

VitalyT :

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()...
            );
Eran :

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 Maps 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.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=103398&siteId=1