Home > database >  Sort list by multiple fields and multiple criteria
Sort list by multiple fields and multiple criteria

Time:02-22

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?

CodePudding user response:

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;
    });

CodePudding user response:

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.getEnd().isAfter(now) && e2.getEnd().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.

  • Related