Ajeetkumar
Ajeetkumar

Reputation: 1329

How do I filter the list based on comparision within list elements in Java 8?

I have a

class MedicationPeriod {
    LocalDateTime startDate, endDate;
    //assume getters and setters
}

Then I have a List<MedicationPeriod> medPrd = getMedPeriods();

Elements in medPrd may have the same startDate.

Now I want to filter the list such that, for elements having the same startDate, the one with the greatest endDate should remain in the list. I.e. having the longest day.

Example: If list elements are:

1) startDate = 2018-Jan-1, endDate = 2018-Feb-25 // 25 days

2) startDate = 2018-Jan-1, endDate = 2018-Feb-20 // 20 days

3) startDate = 2018-Jan-5, endDate = 2018-Feb-25 // startDate is diff, we don't care

So the final list should have only elements 1) and 3). Element 2 will be removed since other MedicationPeriod with the same startDate has a greater endDate.

Here is my attempt (non happily working) to get the result:

mps.stream().collect(Collectors.toMap(MedicationPeriod::getStartDate, e -> e, (a,b) -> a.endDate.isAfter(b.endDate) ? a : b)).values();

My requirement:

  1. I want List<MedicationPeriod> not Collection<MedicationPeriod> as my solution gives Collection<>

  2. I want to achieve this without collecting them and using .values() , because I may do further transformations while in streams and collecting them later.

Let's say I have to perform some test after filtering the MedicationPeriods and then collect it into:

class DateRange {
    LocalDate startDate, endDate;
}

How can I do this with only one terminal operation?

Upvotes: 2

Views: 143

Answers (1)

pvpkiran
pvpkiran

Reputation: 27038

There is nothing wrong with your code. It works. Just did a bit of refactoring

 new ArrayList<>(medPrd.stream()
          .collect(Collectors.toMap(MedicationPeriod::getStartDate, Function.identity(), (a, b) -> a.endDate.isAfter(b.endDate) ? a : b))
          .entrySet()
          .stream()
          .map(entry -> new DateRange(entry.getValue().startDate, entry.getValue().getEndDate())).collect(Collectors.toList()));

Incorporating @Holger 's suggestion it would look like

 new ArrayList<>(medPrd.stream()
      .collect(Collectors.toMap(MedicationPeriod::getStartDate, Function.identity(), BinaryOperator.maxBy(Comparator.comparing(MedicationPeriod::getEndDate))))
      .entrySet()
      .stream()
      .map(entry -> new DateRange(entry.getValue().startDate, entry.getValue().getEndDate())).collect(Collectors.toList()));

Upvotes: 3

Related Questions