By Knut Arne Vedaa


2009-07-30 11:44:47 8 Comments

If I have a simple list of Strings:

List<String> stringList = new ArrayList<String>();

I can sort it with:

Collections.sort(stringList);

But suppose I have a Person class:

public class Person
{
   private String name;
   private Integer age;
   private String country;
}

And a list of it:

List<Person> personList = new ArrayList<Person>();

And I want to sort it sometimes by name, sometimes by age, sometimes by country.

What is the easiest way to accomplish that?

I know that I can implement the Comparable interface, but that seems to limit me to sort it by one specific property.

9 comments

@aioobe 2014-09-03 10:49:19

The Java 8 way of doing this is to use List.sort as follows:

personList.sort(Comparator.comparing(Person::getName));

To quote Stuart Marks in his answer over here.

This is the big advantage of the List.sort(cmp) extension method over Collections.sort(list, cmp). It might seem that this is merely a small syntactic advantage being able to write myList.sort(cmp) instead of Collections.sort(myList, cmp). The difference is that myList.sort(cmp), being an interface extension method, can be overridden by the specific List implementation. For example, ArrayList.sort(cmp) sorts the list in-place using Arrays.sort() whereas the default implementation implements the old copyout-sort-copyback technique.

@Mario Fusco 2009-09-12 07:52:21

Using lambdaj ( http://code.google.com/p/lambdaj/ ) you can achieve what you're asking in the following way:

sort(personList, on(Person.class).getName());

sort(personList, on(Person.class).getAge());

sort(personList, on(Person.class).getCountry());

@Markus Lausberg 2009-07-30 11:46:58

Implement 3 different types of Comparator.

you can add the comparator to the sort command. The comparator you define, will sort the elements by name, age, or what ever.

Collections.sort(list, new Comparator() {

        public int compare(Object arg0, Object arg1) {
            if (!(arg0 instanceof Person)) {
                return -1;
            }
            if (!(arg1 instanceof Person)) {
                return -1;
            }

            Person pers0 = (Person)arg0;
            Person pers1 = (Person)arg1;


            // COMPARE NOW WHAT YOU WANT
            // Thanks to Steve Kuo for your comment!
            return pers0.getAge() - pers1.getAge();
        }
    });

@dfa 2009-07-30 12:18:04

why not using parametric type for Comparator?

@Markus Lausberg 2009-07-30 12:24:49

because i am coming from 1.4 ;)

@Steve Kuo 2009-07-31 15:13:18

You could just return pers0.getAge() - pers1.getAge(). That will work for a three cases (<, > and ==).

@Jason S 2009-07-30 14:31:06

I asked a very similar question (about searching rather than sorting), perhaps there is some useful information (I ended up using an enum that implements Comparator so I pass the enum value as a comparator selector).

@Jörn Horstmann 2009-07-30 13:38:58

You could also use the BeanComparator from apache commons beanutils, like this:

Collections.sort(personList, new BeanComparator("name"));

@Lawrence Tierney 2013-05-20 14:41:11

Nice one. Not seen that before

@Andreas_D 2009-07-30 12:16:28

Collections.sort can be called with a custom comparator. And that comparator can be implemented to allow sorting in different sort orders. Here's an example (for your Person model - with age as an Integer):

public class FlexiblePersonComparator implements Comparator<Person> {
  public enum Order {Name, Age, Country}

  private Order sortingBy = Name;

  @Override
  public int compare(Person person1, Person person2) {
    switch(sortingBy) {
      case Name: return person1.name.compareTo(person2.name);
      case Age: return person1.age.compareTo(person2.age);
      case Country: return person1.country.compareTo(person2.country);
    }
    throw new RuntimeException("Practically unreachable code, can't be thrown");
  }

  public void setSortingBy(Order sortBy) {
    this.sortingBy = sortingBy;
  }
}

And you use it like that (assuming persons is a field):

public void sortPersonsBy(FlexiblePersonComparator.Order sortingBy) {
  List<Person> persons = this.persons;  // useless line, just for clarification
  FlexiblePersonComparator comparator = new FlexiblePersonComparator();
  comparator.setSortingBy(sortingBy);
  Collections.sort(persons, comparator); // now we have a sorted list
}

@dfa 2009-07-30 12:19:16

+1 I like the idea of a flexible comparator

@Knut Arne Vedaa 2009-07-30 13:18:31

You could also pass the sortingBy parameter in a constructor.

@gunalmel 2012-09-16 04:06:33

Answer by @Yishai in this post demonstrates elegant use of enum for custom sorting and grouped sorting (multiple arguments) utilizing comparator chaining.

@Dinesh Phalwadiya 2018-02-16 07:19:41

This should be accepted answer

@Knut Arne Vedaa 2009-07-30 12:19:07

Thanks to the responders. For the benefit of others, I'd like to include a complete example.

The solution is the create the following additional classes:

public class NameComparator implements Comparator<Person>
{
    public int compare(Person o1, Person o2)
    {
       return o1.getName().compareTo(o2.getName());
   }
}

public class AgeComparator implements Comparator<Person>
{
    public int compare(Person o1, Person o2)
    {
        return o1.getAge().compareTo(o2.getAge());
    }
}

public class CountryComparator implements Comparator<Person>
{
    public int compare(Person o1, Person o2)
    {
        return o1.getCountry().compareTo(o2.getCountry());
    }
}

The list can then be sorted like this:

Collections.sort(personList, new NameComparator());
Collections.sort(personList, new AgeComparator());
Collections.sort(personList, new CountryComparator());

@IMustBeSomeone 2016-08-08 01:14:54

Thanks, mate. This one worked, +1, although couldn't you have implemented the comparators themselves straight into the class?

@z5h 2009-07-30 11:48:45

The Collections.sort method can be invoked with a second argument which is the comparator to use. Create 3 comparators and use the one you want when appropriate.

Collections.sort(list , new Comparator() {
        public int compare(Object o1, Object o2) {
          ...
        }
      });

@basszero 2009-07-30 11:51:17

awwww ... Comparator<Person> ... syntatic sugar is tasty!

@roottraveller 2017-07-21 11:07:20

yup, i think too so. it should be Collections.sort(Person , new Comparator<Person>() {

@Michael Borgwardt 2009-07-30 11:48:06

Implement the Comparator interface (once for each different sort order) and use the Collections.sort() method that takes a Comparator as additional parameter.

Related Questions

Sponsored Content

16 Answered Questions

27 Answered Questions

[SOLVED] Sorting an array of JavaScript objects by property

22 Answered Questions

41 Answered Questions

[SOLVED] Sort array of objects by string property value

34 Answered Questions

[SOLVED] How do I sort a dictionary by value?

26 Answered Questions

[SOLVED] How do I sort an NSMutableArray with custom objects in it?

23 Answered Questions

25 Answered Questions

[SOLVED] Sort ArrayList of custom Objects by property

49 Answered Questions

[SOLVED] Sort a Map<Key, Value> by values

19 Answered Questions

[SOLVED] How to Sort a List<T> by a property in the object

Sponsored Content