Ordenando una ArrayList de objetos usando un orden de clasificación personalizado

Estoy buscando implementar una función de clasificación para la aplicación de mi libreta de direcciones.

Quiero ordenar una ArrayList contactArray . Contact es una clase que contiene cuatro campos: nombre, número de casa, número de móvil y dirección. Quiero ordenar el name .

¿Cómo puedo escribir una función de clasificación personalizada para hacer esto?

Aquí hay un tutorial sobre ordenar objetos:

  • Los tutoriales de Java – Colecciones – Pedido de objetos

Aunque daré algunos ejemplos, recomendaría leerlo de todos modos.


Hay varias formas de ordenar una ArrayList . Si desea definir un orden natural (predeterminado), debe permitir que Contact implemente Comparable . Suponiendo que desea ordenar por defecto el name , entonces haga (se omiten las comprobaciones nulas por simplicidad):

 public class Contact implements Comparable { private String name; private String phone; private Address address; public int compareTo(Contact other) { return name.compareTo(other.name); } // Add/generate getters/setters and other boilerplate. } 

para que puedas hacer

 List contacts = new ArrayList(); // Fill it. Collections.sort(contacts); 

Si desea definir un orden externo controlable (que anula el orden natural), entonces necesita crear un Comparator :

 List contacts = new ArrayList(); // Fill it. // Now sort by address instead of name (default). Collections.sort(contacts, new Comparator() { public int compare(Contact one, Contact other) { return one.getAddress().compareTo(other.getAddress()); } }); 

Incluso puede definir los Comparator en el Contact mismo para que pueda volver a utilizarlos en lugar de volver a crearlos cada vez:

 public class Contact { private String name; private String phone; private Address address; // ... public static Comparator COMPARE_BY_PHONE = new Comparator() { public int compare(Contact one, Contact other) { return one.phone.compareTo(other.phone); } }; public static Comparator COMPARE_BY_ADDRESS = new Comparator() { public int compare(Contact one, Contact other) { return one.address.compareTo(other.address); } }; } 

que se puede usar de la siguiente manera:

 List contacts = new ArrayList(); // Fill it. // Sort by address. Collections.sort(contacts, Contact.COMPARE_BY_ADDRESS); // Sort later by phone. Collections.sort(contacts, Contact.COMPARE_BY_PHONE); 

Y para rematar, podría considerar usar un comparador javabean genérico :

 public class BeanComparator implements Comparator { private String getter; public BeanComparator(String field) { this.getter = "get" + field.substring(0, 1).toUpperCase() + field.substring(1); } public int compare(Object o1, Object o2) { try { if (o1 != null && o2 != null) { o1 = o1.getClass().getMethod(getter, new Class[0]).invoke(o1, new Object[0]); o2 = o2.getClass().getMethod(getter, new Class[0]).invoke(o2, new Object[0]); } } catch (Exception e) { // If this exception occurs, then it is usually a fault of the developer. throw new RuntimeException("Cannot compare " + o1 + " with " + o2 + " on " + getter, e); } return (o1 == null) ? -1 : ((o2 == null) ? 1 : ((Comparable) o1).compareTo(o2)); } } 

que puedes usar de la siguiente manera:

 // Sort on "phone" field of the Contact bean. Collections.sort(contacts, new BeanComparator("phone")); 

(como se ve en el código, posiblemente los campos nulos ya están cubiertos para evitar NPE durante el ordenamiento)

Además de lo que ya se publicó, debes saber que desde Java 8 podemos acortar nuestro código y escribirlo así:

 Collection.sort(yourList, Comparator.comparing(YourClass::getFieldToSortOn)); 

o desde List ahora tienen método de sort

 yourList.sort(Comparator.comparing(YourClass::getFieldToSortOn)); 

Explicación:

Desde Java 8, las interfaces funcionales (interfaces con un solo método abstracto, pueden tener más métodos predeterminados o estáticos) se pueden implementar fácilmente usando:

  • arguments -> body lambdas arguments -> body
  • o método referencias source::method .

Como Comparator tiene solo un método abstracto int compare(T o1, T o2) , es una interfaz funcional.

Entonces, en lugar de (ejemplo de la respuesta de @BalusC )

 Collections.sort(contacts, new Comparator() { public int compare(Contact one, Contact other) { return one.getAddress().compareTo(other.getAddress()); } }); 

podemos reducir este código a:

 Collections.sort(contacts, (Contact one, Contact other) -> { return one.getAddress().compareTo(other.getAddress()); }); 

Podemos simplificar esta (o cualquiera) lambda salteando

  • tipos de argumento (Java los inferirá en función de la firma del método)
  • o {return}

Entonces, en lugar de

 (Contact one, Contact other) -> { return one.getAddress().compareTo(other.getAddress(); } 

podemos escribir

 (one, other) -> one.getAddress().compareTo(other.getAddress()) 

También ahora Comparator tiene métodos estáticos como comparing(FunctionToComparableValue) o comparing(FunctionToValue, ValueComparator) que podríamos usar para crear fácilmente comparadores que deberían comparar algunos valores específicos de los objetos.

En otras palabras, podemos reescribir el código anterior como

 Collections.sort(contacts, Comparator.comparing(Contact::getAddress)); //assuming that Address implements Comparable (provides default order). 

Esta página le dice todo lo que necesita saber sobre la ordenación de colecciones, como ArrayList.

Básicamente, necesitas

  • hacer que su clase de Contact implemente la interfaz Comparable por
    • creando un método public int compareTo(Contact anotherContact) dentro de él.
  • Una vez que haga esto, puede simplemente llamar a Collections.sort(myContactList); ,
    • donde myContactList es ArrayList (o cualquier otra colección de Contact ).

También hay otra forma, que implica la creación de una clase de comparación, y también puede leer sobre eso desde la página vinculada.

Ejemplo:

 public class Contact implements Comparable { .... //return -1 for less than, 0 for equals, and 1 for more than public compareTo(Contact anotherContact) { int result = 0; result = getName().compareTo(anotherContact.getName()); if (result != 0) { return result; } result = getNunmber().compareTo(anotherContact.getNumber()); if (result != 0) { return result; } ... } } 

BalusC y bguiz ya han dado respuestas muy completas sobre cómo usar los comparadores incorporados de Java.

Solo quiero agregar que google-collections tiene una clase de orden que es más “potente” que los comparadores estándar. Vale la pena echarle un vistazo. Puedes hacer cosas geniales, como componer pedidos, invertirlos, ordenar dependiendo del resultado de una función para tus objetos …

Aquí hay una publicación de blog que menciona algunos de sus beneficios.

Debe hacer que sus clases de Contact implementen Comparable , y luego implemente el compareTo(Contact) . De esta forma, Collections.sort podrá ordenarlos por usted. Según la página a la que me he vinculado, compareTo ‘devuelve un número entero negativo, cero o entero positivo ya que este objeto es menor, igual o mayor que el objeto especificado.’

Por ejemplo, si desea ordenar por nombre (de la A a la Z), su clase se vería así:

 public class Contact implements Comparable { private String name; // all the other attributes and methods public compareTo(Contact other) { return this.name.compareTo(other.name); } } 

Al usar lambdaj puede ordenar una colección de sus contactos (por ejemplo, por su nombre) como sigue

 sort(contacts, on(Contact.class).getName()); 

o por su dirección:

 sort(contacts, on(Contacts.class).getAddress()); 

y así. Más en general, ofrece una DSL para acceder y manipular sus colecciones de muchas maneras, como filtrar o agrupar sus contactos según algunas condiciones, agregar algunos de sus valores de propiedad, etc.

The Collections.sort es una buena implementación de tipo. Si no tiene implementado el comparable para Contact, tendrá que pasar una implementación de Comparator

De nota:

El algoritmo de clasificación es un mergesort modificado (en el que se omite la combinación si el elemento más alto en la sublista baja es menor que el elemento más bajo en la sublista alta). Este algoritmo ofrece un rendimiento n log (n) garantizado. La lista especificada debe ser modificable, pero no es necesario cambiar su tamaño. Esta implementación vuelca la lista especificada en una matriz, ordena la matriz y repite la lista restableciendo cada elemento desde la posición correspondiente en la matriz. Esto evita el rendimiento n2 log (n) que resultaría de intentar ordenar una lista vinculada en su lugar.

El tipo de combinación es probablemente mejor que la mayoría de los algoritmos de búsqueda que puedes hacer.

Lo hice de la siguiente manera. el número y el nombre son dos arraylist. Tengo que ordenar el nombre. Si se produce un cambio en el nombre de la orden arralista, la matriz de números también cambiará su orden.

 public void sortval(){ String tempname="",tempnum=""; if (name.size()>1) // check if the number of orders is larger than 1 { for (int x=0; x 0) { tempname = name.get(i); tempnum=number.get(i); name.set(i,name.get(i+1) ); name.set(i+1, tempname); number.set(i,number.get(i+1) ); number.set(i+1, tempnum); } } } } } 

Debes usar la función Arrays.sort. Las clases que contienen deben implementar Comparable.