3

I have two date fields in Temp class say validFromDate and asOfDate. I have List with me. I need to set the flag whihc is one of the class attributes to true for the record whose validFromDate is closest to asOfDate

Ex.

List<temp> {
    Temp1:
        asOfDate: 2018-01-04
        validFrom: 2018-01-01
    Temp2:
        asOfDate: 2018-01-04
        validFrom: 2018-01-02
    Temp3:
        asOfDate: 2018-01-04
        validFrom: 2018-01-03
}

o/p should be Temp3 as this validFrom is nearest to asOfdate. I will set the flag to true for this Temp2

How can I achieve this using Java 8 streams?

4
  • last one should be Temp3?
    – Eugene
    Commented Aug 1, 2018 at 13:37
  • 2
    Have you tried any code yet? Commented Aug 1, 2018 at 13:37
  • private Limit getClosestApplicableLimit(List<Limit> limitList, LocalDate asOfDate) { LocalDate currentNearestDate = null; for (Limit limit : limitList) { if (limit.getValidFrom().isBefore(asOfDate) && (currentNearestDate == null || limit.getValidFrom().isAfter(currentNearestDate))) { currentNearestDate = limit.getValidFrom(); applicableLimit = limit; } } return applicableLimit; }
    – Sahil
    Commented Aug 1, 2018 at 13:41
  • I tried above code. But want to know how to do in java streams
    – Sahil
    Commented Aug 1, 2018 at 13:41

3 Answers 3

3
  temp.stream()
      .map(x -> new SimpleEntry<>(x, ChronoUnit.DAYS.between(x.getAsOfDate(), x.getValidFrom())))
      .min(Comparator.comparingLong(Entry::getValue))
      .map(Entry::getKey)
      .orElse(...);

Or simpler:

test.stream()
    .min(Comparator.comparingLong(x -> ChronoUnit.DAYS.between(x.asOfDate , x.validFrom)));
13
  • Can I update the field value in above code and return the list instead of single object
    – Sahil
    Commented Aug 1, 2018 at 13:49
  • @Sahil what would the list contain?
    – Eugene
    Commented Aug 1, 2018 at 13:50
  • Input: List<Temp> : {temp1, validFrom, asOfDate, applicable}...applicable flag should be updated to true for the nearest validFrom date or else false. Finally the list should be updated with applicable flag true or false based on above logic
    – Sahil
    Commented Aug 1, 2018 at 13:52
  • @Sahil you make no sense, you want to sort the List based on that difference?
    – Eugene
    Commented Aug 1, 2018 at 13:54
  • 1
    @Sahil in this case you need to sort first and then update the flag: List<Test> result = test.stream() .sorted(Comparator.comparingLong(x -> ChronoUnit.DAYS.between(x.asOfDate, x.validFrom))) .collect(Collectors.toList()); Spliterator<Test> sp = result.stream().spliterator(); sp.tryAdvance(x -> x.setWhatEverFlag(true)); sp.forEachRemaining(x -> x.setWhatEverFlar(false));
    – Eugene
    Commented Aug 1, 2018 at 14:05
1

You can use ChronoUnit.DAYS.between to calculate the number of days between the dates, then use Stream.min to get the lowest value:

Optional<MyClass> shortestDate = myList.stream()
    .min(
        Comparator.comparingLong(
            item -> ChronoUnit.DAYS.between(item.asOfDate(), item.validFrom())
        )
    );
0
0

We can try sorting your list based on the absolute difference between the asOfDate and the validFrom date, then take the first element from the sorted list. Something like this:

list.sort((Temp t1, Temp t2)
    ->Long.compare(Math.abs(t1.getAsOfDate().getTime() - t1.getValidFrom().getTime()),
        Math.abs(t2.getAsOfDate().getTime() - t2.getValidFrom().getTime())));
System.out.println(list.get(0));

This assumes that your dates are the old school pre Java 8 java.util.Date class. If not, my code would have to change. This also assumes that you are OK with changing the order of the list.

Follow the demo link below which shows that the above lambda sort in fact works on a small set of sample data.

Demo

Edit:

If you don't want to alter the original list, but instead want to just update the single matching Temp element, then you can make a copy of the list and then sort the copy:

List<Temp> copy = new ArrayList<>(list);
// sort copy, per above
// then update the original list
Temp match = copy.get(0);
int index = list.indexOf(match);
list.get(index).setFlag(true);

Not the answer you're looking for? Browse other questions tagged or ask your own question.