• Jobs
  • About Us
  • professionals
    • Home
    • Jobs
    • Courses and challenges
  • business
    • Home
    • Post vacancy
    • Our process
    • Pricing
    • Assessments
    • Payroll
    • Blog
    • Sales
    • Salary Calculator

0

270
Views
Sort list by multiple fields and multiple criteria

I have the following code:

list.sort(Comparator
    .comparing(ProgrammData::getEnd)
    .thenComparing(ProgrammData::getStart).reversed());

My problem is that I want to have my list sorted by multiple things: 1.) Group them into future events and past events (By checking if the System.currentMilliseconds() is larger than the end timestamp) 2.) Sort future events by start ascending 3.) Sort past events by end descending

Can I do this with Java 8 Lambda or do I need another way of sorting the items?

Example:

events could look like this:
name, start, end
event1, 2022-02-220100, 2022-02-220300 
event2, 2022-02-220200, 2022-02-241800
event3, 2022-02-251200, 2022-02-281500
event4, 2022-02-261600, 2022-02-262100

if now() is 2022-02-221200 So the order should be:

event3 (next item in the future)
event4 (2nd next item in the future)
event2 (Ended closer to now than event1)
event1 (Longest in the past)
over 3 years ago · Santiago Trujillo
4 answers
Answer question

0

Try this :

    final long currentTime = System.currentTimeMillis();
    list.sort((el1, el2) -> {
        if (el1.equals(el2)) {
            return 0;
        }
        boolean isEl1Future = el1.getEnd().getTime() > currentTime;
        boolean isEl2Future = el2.getEnd().getTime() > currentTime;
        if (isEl1Future != isEl2Future) {
            return isEl1Future ? -1 : 1;
        }
        if (Boolean.TRUE.equals(isEl1Future)) {
            return el1.getStart().before(el2.getStart()) ? -1 : 1;
        }
        return el1.getEnd().after(el2.getEnd()) ? -1 : 1;
    });
over 3 years ago · Santiago Trujillo Report

0

There are multiple things to notice. First, one is the .thenComparing(...) method, which is only taking place if the previous comparing results are equal. You can read more about its behavior in the docs.

Second, if I were you I wouldn't bother to overuse the stream if I could solve it with one simple comparator. Assuming that you are looking for a new instance of the ProgrammData list, I wrote my code in stream style, but the Comparator can be used with the List's sort method.

private List<ProgrammData> sortedProgramms(List<ProgrammData> dataList) {
    final LocalDateTime now = LocalDateTime.now();
    return dataList.stream()
                    .sorted((e1, e2) -> {
                        if (e1.getStart().isAfter(now) && e2.getStart().isAfter(now)) {
                            return e1.getStart().compareTo(e2.getStart());
                        }
                        return e2.getEnd().compareTo(e1.getEnd());
                    })
                    .collect(Collectors.toList());
 }

The LocalDateTime().now() is using System.currentTimeMillis() inside, if there is not a more accurate given clock.

over 3 years ago · Santiago Trujillo Report

0

You need to split past and future events in different lists and sort them accordingly. The final step is to join both lists.

  public static void main(String[] args) {
    ProgrammData programmData1 = new ProgrammData("a", LocalDateTime.now().plusDays(1),
        LocalDateTime.now().plusDays(1));
    ProgrammData programmData2 = new ProgrammData("b", LocalDateTime.now().plusDays(2),
        LocalDateTime.now().plusDays(2));
    ProgrammData programmData3 = new ProgrammData("c", LocalDateTime.now().minusDays(1),
        LocalDateTime.now().minusDays(1));
    ProgrammData programmData4 = new ProgrammData("c", LocalDateTime.now().minusDays(2),
        LocalDateTime.now().minusDays(2));

    List<ProgrammData> programmDataList = new ArrayList<>();

    programmDataList.add(programmData1);
    programmDataList.add(programmData2);
    programmDataList.add(programmData3);
    programmDataList.add(programmData4);

    final List<ProgrammData> collect = programmDataList.stream().sorted(Comparator
        .comparing(ProgrammData::end)).toList();

    LocalDateTime localDateTime = LocalDateTime.now();
    final List<ProgrammData> pastEvents = collect.stream().filter(pd -> pd.end.isBefore(localDateTime))
        .sorted(Comparator
            .comparing(ProgrammData::end).reversed()).toList();
    final List<ProgrammData> futureEvents = collect.stream().filter(pd -> pd.end.isAfter(localDateTime)).toList();

    List<ProgrammData> sortedListAsRequired = new ArrayList<>();

    sortedListAsRequired.addAll(futureEvents);
    sortedListAsRequired.addAll(pastEvents);

    System.out.println(sortedListAsRequired);
  }

  static record ProgrammData(String name, LocalDateTime start, LocalDateTime end) {

  }

The result is something like this:

[ProgrammData[name=a, start=2022-02-23T18:08:59.564300200, end=2022-02-23T18:08:59.568806900], ProgrammData[name=b, start=2022-02-24T18:08:59.568806900, end=2022-02-24T18:08:59.568806900], ProgrammData[name=c, start=2022-02-21T18:08:59.568806900, end=2022-02-21T18:08:59.568806900], ProgrammData[name=c, start=2022-02-20T18:08:59.568806900, end=2022-02-20T18:08:59.568806900]]
over 3 years ago · Santiago Trujillo Report

0

Your example is confusing. As you state in the heading event2 should be handled as if it's in the future, due it's end time (2022-02-241800) is after now (2022-02-221200), so the ordered elements shoud be

event2
event3
event4
event1

If that's correct, you could try something like the following:

events.sort((e1, e2) -> {
    // -1: e1 and e2 in the past
    //  0: e1 and e2 in distinct periods
    // +1: e1 and e2 in the future
    int period = Integer.signum(
          Integer.signum(e1.getEnd().compareTo(now))
        + Integer.signum(e2.getEnd().compareTo(now))
    );
    if (period == 0) {
        return -e1.getEnd().compareTo(now);
    }
    // > 0: e1 is after e2
    // = 0: e1 is equal to e2
    // < 0: e1 is before e2
    int comparation = e1.getComparingDateTime(now).compareTo(
        e2.getComparingDateTime(now)
    );
    return period * comparation;
});

Given

class ProgramData {
    ...
    public LocalDateTime getComparingDateTime(LocalDateTime reference) {
        if (reference.isAfter(end)) {
            // Past
            return end;
        }
        // Future
        return start;
    }
    ...
}
over 3 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Our process Sales
Legal
Terms and conditions Privacy policy
© 2025 PeakU Inc. All Rights Reserved.

Andres GPT

Recommend me some offers
I have an error