Home > Software design >  Java stream not filtering multiple condition , groupby month value of date and calculating sum value
Java stream not filtering multiple condition , groupby month value of date and calculating sum value

Time:11-20

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();
  • Related