2009-07-30 3 views
54

Если у меня есть простой список строк:Сортировка коллекции объектов

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

можно сортировать его:

Collections.sort(stringList); 

Но предположим, что у меня есть класс Person:

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

И его список:

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

И я хочу отсортировать его по названию, иногда по возрасту, иногда по странам.

Что это самый простой способ добиться этого?

Я знаю, что я могу реализовать интерфейс Comparable, но это, по-видимому, ограничивает меня сортировкой по одному конкретному свойству.

+2

Возможно, вы не должны использовать прилагательное «композитный» в названии, поскольку это звучит как композитный шаблон ... – fortran

ответ

33

Реализовать интерфейс Comparator (один раз для каждого различного порядка сортировки) и использовать Collections.sort() метод, который принимает компаратор в качестве дополнительного параметра.

3

Внесите 3 различных типа компаратора.

Вы можете добавить компаратор к команде сортировки. Определяющий компаратор будет сортировать элементы по имени, возрасту или тому, что когда-либо.

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

почему бы не использовать параметрический тип для компаратора? – dfa

+1

, потому что я родом из 1.4;) –

+2

Вы можете просто вернуть pers0.getAge() - pers1.getAge(). Это будет работать в трех случаях (<, > и ==). –

2

Метод Collections.sort может быть вызван вторым аргументом, который используется компаратором. Создайте 3 компаратора и используйте тот, который вам нужен, когда это необходимо.

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

awwww ... Компаратор ... синтаксический сахар вкусный! – basszero

+0

yup, я тоже думаю. это должно быть 'Collections.sort (Person, new Comparator () {' – roottraveller

48

Коллекции.sort можно вызвать с помощью специализированного компаратора. И этот компаратор может быть реализован, чтобы сортировать в разных порядках сортировки. Вот пример (для модели Person - с возрастом как 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; 
    } 
} 

И вы используете его как то (предполагая, что человек это поле):

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 
} 
+2

+1 Мне нравится идея гибкого компаратора – dfa

+4

Вы также можете передать параметр sortingBy в конструкторе. –

+0

[Ответа на этот вопрос @Yishai в этом сообщении] (http://stackoverflow.com/questions/1421322/how-do-i-sort-a-list-with-multiple-sort-parameters#1421537) демонстрирует элегантное использование перечисления для пользовательской сортировки и группировки сортировки (несколько аргументов) используя цепную связь компаратора. – gunalmel

15

Благодаря ответившими. В интересах других я хотел бы привести полный пример.

Решение является создать следующие дополнительные классы:

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

список может быть отсортирован как это:

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

Спасибо, помощник. Это работало +1, хотя вы не могли реализовать сами компараторы прямо в классе? – IMustBeSomeone

5

Вы также можете использовать BeanComparator от Apache Commons BeanUtils, как это :

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

Ницца. –

0

Я спросил very similar question (о поиск, а не сортировка), возможно, есть некоторая полезная информация (в итоге я использовал enum, который реализует Comparator, поэтому я передаю значение enum в качестве селектора компаратора).

0

Использование lambdaj (http://code.google.com/p/lambdaj/) вы можете добиться того, что вы спрашиваете, следующим образом:

рода (personList, на (Person.class) .getName());

вид (человекList, on (Person.class) .getAge());

вид (человекList, on (Person.class) .getCountry());

9

Java-8 способ сделать это состоит в использовании List.sort следующим образом:

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

Stuart Marks Цитируя в своем ответе над here.

Это большое преимущество метода расширения по сравнению с Collections.sort(list, cmp). Может показаться, что это всего лишь небольшое синтаксическое преимущество, заключающееся в возможности писать myList.sort(cmp) вместо Collections.sort(myList, cmp). Разница заключается в том, что myList.sort(cmp), являющийся расширением интерфейса, может быть переопределен конкретным List. Например, ArrayList.sort(cmp) сортирует список на месте с использованием Arrays.sort(), тогда как реализация по умолчанию реализует старый метод копирования-сортировки.