Sorting a collection of objects [duplicate]

2018-12-31 12:35发布

问题:

This question already has an answer here:

  • Sorting an ArrayList of objects using a custom sorting order 10 answers

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.

回答1:

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



回答2:

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
}


回答3:

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


回答4:

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.



回答5:

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

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


回答6:

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


回答7:

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


回答8:

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).



回答9:

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