I want to create a list of persons sorted by LocalDate and String as well as aggregated by duration.
I did some research regarding the use of duration in streams:
- How to get the average duration for each category having films using stream API java
- Using streams to sum a collection of immutable `Duration` objects, in Java
and on using streams with grouping and reducing a list of objects into subgroups:
However, it's impossible for me to solve my problem, class Person looks like this:
class Person {
private LocalDate startDate;
private String personType;
private Duration time1;
private Duration time2;//constructor, getter+setter, other methods
}
An example of the created list looks like this:
List<Person> personList = Arrays.asList(
new Person("2023-02-02","member1","08:00","4:00"),
new Person("2023-02-02","member1","50:00","0:45"),
new Person("2023-02-02","member2","10:00","0:40"),
new Person("2023-02-02","member2","01:00","1:20"),
new Person("2023-02-03","member1","08:00","2:00"),
new Person("2023-02-03","member1","10:00","0:45"),
new Person("2023-02-03","member2","10:00","1:40"),
new Person("2023-02-03","member2","02:00","1:20"),//...
);
I want to create a list of persons sorted by startdate and personType, with the sum of duration.
Desired output:
("2023-02-02","member1","58:00","4:45"),
("2023-02-02","member2","11:00","2:00"),
("2023-02-03","member1","18:00","2:45"),
("2023-02-03","member2","12:00","3:00"),
...
My approach is to use something like this. However, I can't map duration and string values:
Map<LocalDate,List<Person>> result=personList.stream()
.collect(Collectors.groupingBy(Person::getstartDate))
.entrySet().stream()
.collect(Collectors.toMap(x -> {
//how to sum duration values in here?
// Duration duration1 = x.getValue().stream() ...;
//how to use String values in here?
// String string = x.getValue().stream()....
return new Person(x.getKey(), string, duration1,duration2);
}, Map.Entry::getValue));
One way to do it is with a cascade of groupings and a reduction to sum the durations. The following results in a 2-level map that contains the sum per date and type:
If you want a list (the map gives richer information, but it's your application), you can flatten and sort the previous map as follows:
EDIT: As per the comments from Holger, the above can be simplified using
toMapinstead of thegroupingBy/reducingcombination, with the added advantage of simplifying the second operation (toList) by removing the.filter().map()combo:EDIT 2: I used the following
Personclass:And initialize the list as:
All this code is giving me the desired outcome from the question.