2009-07-30 27 views
54

Si tengo una simple lista de cadenas:Ordenar una colección de objetos

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

que puede solucionar el problema con:

Collections.sort(stringList); 

Pero supongamos que tengo una clase Persona:

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

Y una lista de ello:

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

Y quiero ordenarlo a veces por nombre, a veces por edad, a veces por país.

¿Cuál es la forma más fácil de lograr eso?

Sé que puedo implementar la interfaz Comparable, pero eso parece limitarme a clasificarlo por una propiedad específica.

+2

tal vez no debería usar el adjetivo "compuesto" en el título, ya que suena como el patrón compuesto ... – fortran

Respuesta

33

implementar la interfaz Comparator (una vez para cada orden de clasificación diferente) y utilizar el método Collections.sort() que toma un Comparador como parámetro adicional.

3

Implemente 3 tipos diferentes de comparador.

puede agregar el comparador al comando ordenar. El comparador que defina clasificará los elementos por nombre, antigüedad o lo que sea.

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

¿por qué no usar el tipo paramétrico para el comparador? – dfa

+1

porque vengo de 1.4;) –

+2

Puede devolver pers0.getAge() - pers1.getAge(). Eso funcionará para tres casos (<, > y ==). –

2

El método Collections.sort se puede invocar con un segundo argumento que es el comparador a usar. Crea 3 comparadores y usa el que quieras cuando sea apropiado.

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

awwww ... Comparador ... azúcar sintético es sabroso! – basszero

+0

sí, creo que también. debería ser 'Collections.sort (Persona, nuevo comparador () {' – roottraveller

48

Se puede llamar Collections.sort con un comparador personalizado. Y ese comparador se puede implementar para permitir la clasificación en diferentes órdenes de clasificación. He aquí un ejemplo (para el modelo de persona - con la edad como un entero):

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

y se utiliza de esa manera (suponiendo personas es un campo):

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 Me gusta la idea de un comparador flexible – dfa

+4

También podría pasar el parámetro sortingBy en un constructor. –

+0

[Respuesta de @Yishai en este post] (http://stackoverflow.com/questions/1421322/how-do-i-sort-a-list-with-multiple-sort-parameters#1421537) demuestra un uso elegante de enum para la clasificación personalizada y la clasificación agrupada (argumentos múltiples) utilizando el encadenamiento del comparador. – gunalmel

15

Gracias a los respondedores. Para el beneficio de otros, me gustaría incluir un ejemplo completo.

La solución es la creación de las siguientes clases adicionales:

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

La lista a continuación, se puede clasificar así:

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

Gracias, amigo. Este trabajó, +1, aunque no podría haber implementado los comparadores directamente en la clase? – IMustBeSomeone

5

También es posible usar el BeanComparator de Commons BeanUtils apache, como este :

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

Bueno uno. No visto antes –

0

Le pregunté a very similar question (about buscando en lugar de ordenar), tal vez haya alguna información útil (terminé usando un enum que implementa Comparator, así que paso el valor enum como selector de comparador).

0

Usando lambdaj (http://code.google.com/p/lambdaj/) se puede lograr lo que preguntas de la siguiente manera:

especie (personList, en (Person.class) .getName());

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

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

9

La forma de Java 8 de hacer esto es utilizar List.sort de la siguiente manera:

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

Para citar Stuart Marks en su respuesta sobre here.

Esta es la gran ventaja del método de extensión List.sort(cmp) sobre Collections.sort(list, cmp). Puede parecer que esto es simplemente una pequeña ventaja sintáctica al poder escribir myList.sort(cmp) en lugar de Collections.sort(myList, cmp). La diferencia es que myList.sort(cmp), siendo un método de extensión de interfaz, se puede anular mediante la implementación específica List. Por ejemplo, ArrayList.sort(cmp) ordena la lista in situ usando Arrays.sort() mientras que la implementación predeterminada implementa la antigua técnica de copiado-ordenado-copiado.

Cuestiones relacionadas