I have a problem about writing a java stream by filtering multiple condition, grouping by month of the date and calculating the sum of person.
I store the values as Map<String(pId),List<Person>>
Here is my Person class shown below
public class Person{
private String id;
private String name;
private String surname;
private Statement event; // JOIN , EXIT
private Object value;
private LocalDate eventDate;
}
Here is the list
ID,Info,Date (All values are stored in Person object defined in the List)
per1, JOIN, 10-01-2022
per2, JOIN, 10-01-2022
per3, EXIT, 10-01-2022
per3 EXIT, 10-02-2022
per4, JOIN, 10-03-2022
What I want to do is to get this result.
Month Info Total Number
1 JOIN 2
1 EXIT 1
2 EXIT 1
3 JOIN 1
Here is my dto shown below.
public class DTO {
private int month;
private State info; // State -> enum
private int totalEmployees;
}
Here is my GroupDto shown below.
public class GroupDto {
private int month;
private State info;
}
Here is the code snippet but I cannot complete it.
List<DTO > result = persons .values().stream()
.flatMap(List::stream)
.filter(person -> person .getInfo() == Value.ONBOARD || person .getInfo() == Value.EXIT)
.collect(Collectors.groupingBy(
p -> new GroupDto(p.getEventDate().getMonthValue(), p.getEvent()),
Collectors.counting()
))
.entrySet().stream()
.map(e -> new DTO(p.getKey().get, p.getKey(), (int) (long) e.getValue())) // -> ERROR Line
.sorted(Comparator.comparing(MonthWiseDto::getMonth))
.toList();
How can I do that?
CodePudding user response:
public class Main {
public static void main(String... args) {
List<Person> persons = List.of(
new Person("per1", Statement.JOIN, LocalDate.of(2022, 1, 10)),
new Person("per2", Statement.JOIN, LocalDate.of(2022, 1, 10)),
new Person("per3", Statement.EXIT, LocalDate.of(2022, 1, 10)),
new Person("per3", Statement.EXIT, LocalDate.of(2022, 2, 10)),
new Person("per4", Statement.JOIN, LocalDate.of(2022, 3, 10)));
List<Dto> groupResults = calculateGroupResults(persons);
groupResults.forEach(System.out::println);
}
public static List<Dto> calculateGroupResults(List<Person> persons) {
Map<GroupKey, Long> map = persons.stream()
.filter(person -> person.getEvent() == Statement.EXIT || person.getEvent() == Statement.JOIN)
.collect(Collectors.groupingBy(
person -> new GroupKey(person.getEventDate().getMonthValue(), person.getEvent()),
Collectors.counting()));
return map.entrySet().stream()
.map(entry -> new Dto(entry.getKey().getMonth(), entry.getKey().getInfo(), entry.getValue()))
.sorted(Dto.SORT_BY_MONTH_INFO)
.collect(Collectors.toList());
}
enum Statement {
JOIN,
EXIT
}
@Getter
@RequiredArgsConstructor
public static final class Person {
private final String id;
private final Statement event;
private final LocalDate eventDate;
}
@Getter
@EqualsAndHashCode
@RequiredArgsConstructor
public static final class GroupKey {
private final int month;
private final Statement info;
}
@Getter
@RequiredArgsConstructor
public static final class Dto {
public static final Comparator<Dto> SORT_BY_MONTH_INFO =
Comparator.comparing(Dto::getMonth)
.thenComparingInt(one -> one.getInfo().ordinal());
private final int month;
private final Statement info;
private final long totalEmployees;
@Override
public String toString() {
return month "-" info '-' totalEmployees;
}
}
}
Demo
1-JOIN-2
1-EXIT-1
2-EXIT-1
3-JOIN-1
CodePudding user response:
Assuming that you want to get the total number of people for every combination of Month and State you need to group the data based on these two properties.
For that, you can define an object that would serve as a key in the intermediate Map. It can be implemented as a record like that:
public record MonthState(int mont, State info) {}
In the stream, we can make use of the Collector groupingBy()
with Collector counting()
passed as a downstream to generate the total number of Person
objects having particular combination of month and state.
Map<String, List<Person>> personListById = // initializing the map
List<DTO> result = personListById.values().stream()
.flatMap(List::stream)
.filter(per -> per.getInfo() == State.EXIT || per.getInfo() == State.JOIN)
.collect(Collectors.groupingBy(
p -> new MonthState(p.getEventDate().getMonthValue(), p.getInfo()),
Collectors.counting()
))
.entrySet().stream()
.map(e -> new DTO(e.getKey().mont(), e.getKey().info(), (int) (long) e.getValue()))
.sorted(Comparator.comparing(DTO::getMonth))
.toList();