1

I have a nested maps object like below

{12345={{"status":"200","outcome":"Success","message":"Account created"}}
{23121={{"status":"400","outcome":"Exception","message":"Invalid State value"}}
{43563={{"status":"200","outcome":"Success","message":"Account updated"}}
{72493={{"status":"400","outcome":"Exception","message":"Bad Request"}}

I need to transform this into Map<String, List<Map<String, Map<String, String>>> where the key of outer map is value of the status ( 200 or 400 ) and the value is the list of original maps that have status = 200 or 400 or other valid values from the inner map.

So, the new structure would look like

{{200={[{12345={"status":"200","outcome":"Success","message":"Account created"}},
       {43563={"status":"200","outcome":"Success","message":"Account updated"}}
      ]
     },
{400={[{23121={"status":"400","outcome":"Exception","message":"Invalid State value"}},
       {72493={"status":"400","outcome":"Exception","message":"Bad Request"}}
      ]
     }
}

Ultimately, I need to generate a report based on the different stati.

This is what I have started with, but am stuck.

I want to loop through outer map, get the inner map, get the value of status key and add the map to a list based on status code value.

This is how I am doing it using loops

private static Map<String, List<Map<String, Map<String, String>>>> covertToReport(Map<String, Map<String, String>> originalMap) {
    Map<String, List<Map<String, Map<String, String>>>> statusBasedListOfMaps = new TreeMap<>();
    //loop through the map
    //for each key, get the inner map
    //get the status value for each inner map

    List<Map<String, Map<String, String>>> accountsMapsList;
    for (Entry<String, Map<String, String>> entry : originalMap.entrySet()) {
        String accNum = entry.getKey();
        Map<String, String> childMap = entry.getValue();
        String stausVal = childMap.get("status");
        accountsMapsList = statusBasedListOfMaps.get(stausVal) == null ? new ArrayList<>() : statusBasedListOfMaps.get(stausVal);
        accountsMapsList.add((Map<String, Map<String, String>>) entry);
        statusBasedListOfMaps.put(stausVal, accountsMapsList);
    }
    return statusBasedListOfMaps;
}

Of course, the below code doesn't compile, but that is what I am trying to get.

private static void covertToReport(Map<String, Map<String, String>> originalMap) {
    Map<String, List<Map<String, Map<String, String>>>> statusBasedListOfMaps;

    statusBasedListOfMaps = originalMap.entrySet()
       .stream()
       .filter(e -> e.getValue()
          .values()
          .stream()
          .map(innerMap -> Collectors.toList())
       .collect(Collectors.toMap(Map.Entry::getKey, Collectors.toList(e)));

Is this possible?

2 Answers 2

2

You can just use Collectors.groupingBy() with Collectors.mapping():

private static Map<String, List<Map<String, Map<String, String>>>> convertToReport(Map<String, Map<String, String>> originalMap) {
    return originalMap.entrySet().stream()
            .collect(Collectors.groupingBy(e -> e.getValue().get("status"), 
                    Collectors.mapping(Map::ofEntries, Collectors.toList())));
}

You group by status and then map the associated entry to an own map using Map.ofEntries(). If you are using Java you can use this instead of Map::ofEntries:

e -> new HashMap<>() {{ put(e.getKey(), e.getValue()); }}

The result will be this:

200=[
    {12345={status=200, message=Account created, outcome=Success}}, 
    {43563={status=200, message=Account created, outcome=Success}}
],
400=[
    {72493={status=400, message=Invalid State value, outcome=Exception}}, 
    {23121={status=400, message=Invalid State value, outcome=Exception}}
]
Sign up to request clarification or add additional context in comments.

Comments

0

Your function return a Map<String, List<Map<String, Map<String, String>>>>, but your structure look like Map<String, Map<String, Map<String, String>>>

If what you really like is a Map<String, Map<String, Map<String, String>>> here is the code: Map<String, Map<String, Map<String, String>>> result= map.entrySet().stream().collect(Collectors.groupingBy(entry -> entry.getValue().get("status"), Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));

1 Comment

The above code did work well for Map<String, Map<String, Map<String, String>>>. And it is also concise which will definitely be useful. But for this particular requirement, I needed a List, so I accepted the other answer. But thank you for this as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.