Code Review Asked by user9492428 on December 31, 2021
Not sure if I am overcomplicating the requirement but this is what I need (for simplicity I will show a the List<Map<String, Object>>
as a JSON
):
[
{
"project": "Project1",
"workType": "Dev",
"taskTitle": "Dev Title 1",
"effort": 150
},
{
"project": "Project1",
"workType": "Dev",
"taskTitle": "Dev Title 2",
"effort": 200
},
{
"project": "Project1",
"workType": "QA",
"taskTitle": "QA Title 1",
"effort": 50
},
{
"project": "Project1",
"workType": "QA",
"taskTitle": "QA Title 2",
"effort": 25
},
{
"project": "Project2",
"workType": "Dev",
"taskTitle": "Dev Title 3",
"effort": 300
},
{
"project": "Project2",
"workType": "Dev",
"taskTitle": "Dev Title 4",
"effort": 300
},
{
"project": "Project2",
"workType": "QA",
"taskTitle": "QA Title 3",
"effort": 125
},
{
"project": "Project2",
"workType": "QA",
"taskTitle": "QA Title 4",
"effort": 125
}
]
I want to process a HashMap which is equivalent to the above to produce a HashMap equivalent to below:
[
{
"project": "Project1",
"effort": 425, // sum of all efforts
"types": [
{
"workType": "Dev",
"effort": 350 // sum of all effort where workType == Dev
},
{
"workType": "QA",
"effort": 75 // sum of all effort where workType == QA
}
]
},
{
"project": "Project2",
"effort": 850, // sum of all efforts
"types": [
{
"workType": "Dev",
"effort": 600 // sum of all effort where workType == Dev
},
{
"workType": "QA",
"effort": 250 // sum of all effort where workType == QA
}
]
}
]
This is the starting point of my attempt:
transformedData.stream().collect(
Collectors.groupingBy(
m -> m.get("project"),
Collectors.mapping( m2 -> m2, Collectors.toList() )
)
);
Unfortunately I am a bit stuck on how to proceed..
UPDATE: The below gives me the expected result but it does not look performance friendly at all..
Map<Object, List<Map<String, Object>>> appGrouping = transformedData.stream().collect(
Collectors.groupingBy(
m -> m.get("project"),
Collectors.mapping(m2 -> m2, Collectors.toList())
)
);
List<Map<String, Object>> finalData = new ArrayList<>();
appGrouping.forEach((k,v) -> {
Map<String, Object> data = new HashMap<>();
data.put("project", k);
data.put("types", new ArrayList<>());
v.stream().collect(
Collectors.groupingBy(
m -> m.get("workType"),
Collectors.summingDouble(m -> getDoubleVal(m.get("effort")))
)
).forEach((k2,v2) -> {
Map<String, Object> data2 = new HashMap<>();
data2.put("workType", k2);
data2.put("effort", v2);
getFromMap(data, "types", List.class).add(data2); // this is a util method I wrote to get a value from a map
Double totalEffort = Objects.requireNonNull(getFromMap(data, "effort", Double.class)) + v2;
data.put("effort", totalEffort);
});
finalData.add(data);
});
Here is one way to get it in a single pass.
Map<String, Map<String, Object>> tempMap = new HashMap<String, Map<String, Object>>();
transformedData.forEach(i -> {
Double currentEffort = (Double) i.get("effort");
Map<String, Object> subMap =
tempMap.computeIfAbsent((String)i.get("project"),
(k) -> new HashMap<String, Object>(){{
put("project", (String)i.get("project"));
put("effort", 0.0D);
put("types", new HashMap<String, Double>());}});
subMap.merge("effort", currentEffort, (o, n) -> (Double)o + (Double)n);
((Map<String, Double>)subMap.get("types"))
.merge((String) i.get("workType"), currentEffort, (o, n) -> (Double)o + (Double)n);
});
List<Map<String, Object>> finalData = (List<Map<String, Object>>) tempMap.values();
The finalData object converted to JSON (using your data above as input) is the below. I've changed the types object from a list of maps to a map of workType to effort.
[
{
"types": {
"QA": 250.0,
"Dev": 600.0
},
"project": "Project2",
"effort": 850.0
},
{
"types": {
"QA": 75.0,
"Dev": 350.0
},
"project": "Project1",
"effort": 425.0
}
]
Answered by jnorman on December 31, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP