Home > Software engineering >  Java - How to create a new map containing summed fields from a map containing a key and list of fiel
Java - How to create a new map containing summed fields from a map containing a key and list of fiel

Time:12-28

I am provided with a List<Result>

The Result class has a number of fields of which five are of interest

class Result {
   
    public enum SESSION_TYPE {
        NIGHT,
        DAY
    }

    private SESSION_TYPE sessionType;
    private String sessionDateTime;
    private String sessionDate;
    private Double consumed;
    private Double cost;

    ...
    getters and setters 

}
  

I have created a map as follows


Map<String,List<Result>> dailyResults = results.stream().collect(Collectors.groupingBy(Result::getSessionDate));

I would now like to create a new map keyed on the same sessionDate which contains the summed consumed and cost fields grouped by the SESSION_TYPE, thus

Map<String, Map<String,SessionDetail>> sessionResults

i.e., Map<SessionDate, Map<SessionType,SessionDeatail>>

where the SessionDetail is a record as follows -

record SessionDetail(Result.SESSION_TYPE sessionType, Double consumedTotal, Double costTotal) {};

I've spent some time on this without achieving the desired result. Any help would be much appreciated.

CodePudding user response:

You can do as follows:

Here is some data.

List<Result> results = new ArrayList<>(List.of(
        new Result(Result.SESSION_TYPE.DAY, "T1", "27-Dec-2022", 10., 1.),
        new Result(Result.SESSION_TYPE.DAY, "T1", "27-Dec-2022", 10., 2.),
        new Result(Result.SESSION_TYPE.DAY, "T1", "27-Dec-2022", 10., 3.),
        new Result(Result.SESSION_TYPE.NIGHT, "T1", "26-Dec-2022", 10., 20.),
        new Result(Result.SESSION_TYPE.NIGHT, "T1", "26-Dec-2022", 10., 30.),
        new Result(Result.SESSION_TYPE.DAY, "T1", "26-Dec-2022", 10., 40.),
        new Result(Result.SESSION_TYPE.DAY, "T1", "27-Dec-2022", 10., 10.),
        new Result(Result.SESSION_TYPE.DAY, "T1", "27-Dec-2022", 10., 10.)));

The original results can be first categorized by the Date. Then using toMap, take the session type as the key and then create a new instance, summing the values in the previous instance to the one just encountered.

Map<String, Map<Result.SESSION_TYPE, SessionDetail>> dailyResults = results
        .stream()
        .collect(Collectors.groupingBy(Result::getSessionDate,
                Collectors.toMap(Result::getSessionType,
                        r -> new SessionDetail(r.getSessionType(),
                                r.getConsumed(), r.getCost()),
                        (a, b) -> new SessionDetail(b.sessionType,
                                a.consumedTotal   b.consumedTotal,
                                a.costTotal   b.costTotal))));

Print the results as follows:

dailyResults.entrySet().forEach(e -> {
    System.out.println(e.getKey());
    e.getValue().entrySet()
            .forEach(s -> System.out.println("    "   s));
});

prints

27-Dec-2022
    DAY=SessionDetail[sessionType=DAY, consumedTotal=50.0, costTotal=26.0]
26-Dec-2022
    NIGHT=SessionDetail[sessionType=NIGHT, consumedTotal=20.0, costTotal=50.0]
    DAY=SessionDetail[sessionType=DAY, consumedTotal=10.0, costTotal=40.0]

The above works without making any changes to your classes. Since record values are final a new record much be created to replace the previous one using the accumulated sums.

  • Related