Ordenar elementos
En programación hay operaciones tan necesarias y frecuentes que merece la pena definir una interfaz que las declare. Por ejemplo, comparar dos valores para realizar búsquedas y ordenación.
En Java tenemos un par de interfaces para este cometido: Comparable y Comparator.
Interfaz Comparable
La interfaz Comparable<T> es una interfaz tipada que consta de un único método:
int compareTo(Object obj);
Supongamos que queremos comparar dos objetos o1 y o2. Ejecutamos la siguiente instrucción:
o1.compareTo(o2);
En una ordenación, el método devolverá:
- Si
o1va antes deo2devolverá un número negativo. - Si
o1va después deo2devolverá un número positivo. - Si se consideran iguales a efectos de ordenación, devolverá
0.
Ordenar objetos
Veamos un ejemplo. Queremos ordenar objetos de la clase Persona. Tenemos por lo tanto que escoger un criterio de ordenación. En este caso los ordenaremos por sus ids:
public class Persona implements Comparable<Persona> {
private int id;
private String nombre;
private int edad;
public Persona (int id, String nombre, int edad){
this.id = id;
this.nombre = nombre;
this.edad = edad;
}
@Override // Implementación de la interfaz comparable
public int compareTo(Persona persona) {
if (this.id < persona.id) {
return -1;
}
else if (this.id > persona.id) {
return 1;
}
else{
return 0;
}
}
@Override
public String toString() {
return this.id + " - " + this.nombre + " de " + this.edad + " años";
}
}
El número devuelto no tiene por qué ser 1 o -1, puede ser cualquier número positivo o negativo. Podemos ahora probar el método de esta clase.
Persona p1 = new Persona(3, "Anselmo", 14);
Persona p2 = new Persona(1, "Josefa", 15);
int res = p1.compareTo(p2);
System.out.println(res); // res = 1, porque id=3 es mayor que id=1
Se mostrará por pantalla el número 1 en este caso. En cambio, si cambiamos la tercera línea por int res = p2.compareTo(p1), la variable res tendría el valor -1.
Ordenar arrays de números
La interfaz Comparable fue creada por los creadores de Java y es implementada por otras clases de la API. Una de ellas es la clase Arrays que implementa el método estático sort(). Este método ordena un array en el orden natural de sus elementos.
int[] valores = {5, 3, 6, 9, 3, 4, 1, 0, 10};
Arrays.sort(valores);
En este caso ordenará el array valores de la siguiente manera:
[0, 1, 3, 3, 4, 5 , 6, 9, 10];
Ordenar arrays de objetos
Este método de Arrays también sirve para ordenar arrays de objetos de cualquier clase siempre que tenga implementada la interfaz Comparable. En este caso, utilizará el orden que se indica por la implementación del método compareTo().
Persona[] personas = new Persona[3];
personas[0] = new Persona(2, "Ana", 19);
personas[1] = new Persona(5, "Xurxo", 12);
personas[2] = new Persona(1, "Xoán", 10);
Arrays.sort(personas);
for(Persona persona: personas){
System.out.println(persona.toString());
}
Esto imprimirá las personas en el siguiente orden:
1 - Xoán de 10 años
2 - Ana de 19 años
5 - Xurxo de 12 años
Ordenar colecciones
Para ordenar listas o cualquier otra colección debemos utilizar el método estático sort() pero de la clase Collections.
ArrayList<Persona> personas = new ArrayList<Persona>();
personas.add(new Persona(2, "Ana", 19));
personas.add(new Persona(5, "Xurxo", 12));
personas.add(new Persona(1, "Xoán", 10));
Collections.sort(personas);
for(Persona persona: personas){
System.out.println(persona.toString());
}
Ordenar en orden inverso
Si deseas ordenar una lista de objetos en orden inverso puedes usar Collections.reverse() o Arrays.reverse() para invertir la lista después de haber realizado la ordenación. Esto es útil cuando primero quieres ordenarla de manera natural (de menor a mayor, por ejemplo) y luego invertir la lista para tener el orden completamente opuesto.
ArrayList<Persona> personas = new ArrayList<Persona>();
personas.add(new Persona(2, "Ana", 19));
personas.add(new Persona(5, "Xurxo", 12));
personas.add(new Persona(1, "Xoán", 10));
Collections.sort(personas);
Collections.reverse(personas);
for(Persona persona: personas){
System.out.println(persona.toString());
}
Interfaz Comparator
La interfaz Comparator proporciona un criterio de ordenación a la clase que implementa la ordenación natural. Pero es frecuente que tengamos que ordenar objetos de la misma clase con diferentes criterios. Podemos necesitar un listado alfabético de nombres de una Persona o ordenarlas por edad. Para solucionar esto existe la interfaz Comparator<T>
Esta interfaz define el siguiente método:
int compare(Object ob1, Object ob2);
Recibe dos objetos y debe determinar cuál va antes en un proceso de ordenación.
En una ordenación, el método devolverá:
- Si
o1va antes deo2devolverá un número negativo. - Si
o1va después deo2devolverá un número positivo. - Si se consideran iguales para ese criterio, devolverá
0.
Necesitaremos una clase que implemente Comparator para cada criterio de comparación que queramos implementar.
Ordenar objetos
Vamos a ver cómo podemos ordenar personas (objetos Persona) por sus edades.
En primer lugar, necesitamos crear una clase ComparaEdades que implemente la interfaz Comparator y, con ello, se debe implementar el método compare:
public class ComparaEdades implements Comparator<Persona> {
@Override
public int compare(Persona p1, Persona p2) {
return p1.getEdad() - p2.getEdad();
}
}
Para realizar la comparación utilizando este método lo hacemos de la siguiente manera:
Persona[] personas = new Persona[3];
personas[0] = new Persona(2, "Ana", 19);
personas[1] = new Persona(5, "Xurxo", 12);
personas[2] = new Persona(1, "Xoán", 10);
// Ordenar por edad
ComparaEdades comparador = new ComparaEdades();
Arrays.sort(personas, comparador);
// Mostrar personas ordenadas
for(Persona persona: personas) {
System.out.println(persona.toString());
}
El resultado que obtenemos en pantalla es el siguiente:
1 - Xoán de 10 años
5 - Xurxo de 12 años
2 - Ana de 19 años
Ordenar colecciones
Para ordenar listas o cualquier otra colección debemos utilizar el método estático sort() pero de la clase Collections.
ArrayList<Persona> personas = new ArrayList<Persona>();
personas.add(new Persona(2, "Ana", 19));
personas.add(new Persona(5, "Xurxo", 12));
personas.add(new Persona(1, "Xoán", 10));
Collections.sort(personas, new ComparaEdades());
for(Persona persona: personas){
System.out.println(persona.toString());
}