0

I have collection of persons:

class Person {
    public String name;
    public int count;
    public boolean favorite;

    // getters / setters ...
}

I want to sort collection of persons by:

  1. First display items with favorite=true
  2. Second display items with count > 0
  3. Last display items with count == 0

How can I write this conditions with Comparator from 1.8 JDK and retrieve expected results?

3
  • Have you tried Comparator.comparing(...).thenComparing(...)? Commented Apr 18, 2018 at 10:02
  • 1
    Also, it's unclear whether you want to filter or sort, and if you want to sort, whether items sorted by criterions 2 and 3 should remain in the original order, or whether you could e.g. also just sort by count in descending order. Commented Apr 18, 2018 at 10:03
  • What @tobias_k says is true. are you trying to sort your collections or are you trying to display the person objects by conditions? if it's the second answer, a simple for-loop & if-else statements should suffice Commented Apr 18, 2018 at 10:07

2 Answers 2

2

You can use Comparator.comparing(...).thenComparing(...) to sort by more than one attribute. For sorting favourites first, you can sort by that attribute, but then have to reverse the result, as false sorts before true. Assuming that you want to sort just by whether the count is > 0, and not by the actual value of the count:

List<Person> persons = Arrays.asList(
        new Person("p1", 2, true),
        new Person("p2", 0, false),
        new Person("p3", 0, true),
        new Person("p4", 1, false),
        new Person("p5", 3, true));

persons.stream().sorted(Comparator
            .comparing(Person::isFavorite).reversed()
            .thenComparing(p -> p.getCount() == 0))
    .forEach(System.out::println);

Result:

Person(name=p1, count=2, favorite=true)
Person(name=p5, count=3, favorite=true)
Person(name=p3, count=0, favorite=true)
Person(name=p4, count=1, favorite=false)
Person(name=p2, count=0, favorite=false)

Note that the final count == 0 condition is redundant (assuming that count can not be < 0)

Or sort by count directly and reverse once at the end; this will sort p5 before p1 in the example:

persons.stream().sorted(Comparator
            .comparing(Person::isFavorite)
            .thenComparing(Person::getCount).reversed())
    .forEach(System.out::println);
Sign up to request clarification or add additional context in comments.

Comments

1

Assuming you want to sort your persons and not filter them, you could do the following:

class Person implements Comparable<Person>
{
  ...

  @Override
  int compareTo(Person person)
  {
    // Maye not specified
    if (person == null)
      return (1);

    // Compare 'favorite'
    // Favorites first, so flag=true means smaller
    if (this.favorite && (!person.favorite))
      return (-1);
    else if ((!this.favorite) && person.favorite)
      return (1);

    // Compare 'count'
    // Having count > 0 first, so count=0 means greater
    // Assuming count is never negative
    if ((this.count == 0) && (person.count > 0))
      return (1);
    if ((this.count > 0) && (person.count == 0))
      return (-1);

    // At this point, both persons have the same 'favorite' flag
    // And both have either count=0 or count>0
    // Order by name in that case
    return (this.name.compareTo(person.name));

  } // compareTo

} // class Person

After that, sort your persons:

List<Person> my_persons;
my_persons = ....
Collections.sort(my_persons);

1 Comment

This solution can done even with java 7 and lower versions. Question was to sort list based on java 8 streams.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.