15 dic 2020

Ordenación de colecciones y listas mediante las interfaces Comparable y Comparator en Java

Ordenación de colecciones mediante la interfaz Comparable

Es necesario implementar la interfaz Comparable que declara el método:

int compareTo(Object o);

Este método compara el objeto  sobre el que actúa con el objeto recibido como parámetro.
Este método tiene que devolver un valor negativo si éste objeto es menor que el recibido, 0 si son iguales o un valor positivo si es mayor, según el orden natural de los objetos, que en muchos casos habrá que especificar.
Por ejemplo, para una clase persona, podría interesar ordenar por dni, o por apellidos y nombre, o por nombres y apellidos, etc.

public class Persona implements Comparable {
    private String nombre;
    private String apellidos;
    private String dni;
    private Date fechaNacimiento;   

public int compareTo(Object o) {
        Persona persona = (Persona)o;       

        if(this.apellidos.compareToIgnoreCase(persona.apellidos) == 0) {           
            if(this.nombre.compareToIgnoreCase(persona.nombre) == 0) {
                return this.dni.compareTo(persona.dni);
            } else {
                return this.nombre.compareToIgnoreCase(persona.nombre);
            }
        } else {
            return this.apellidos.compareToIgnoreCase(persona.apellidos);
        }       

    }
}                          
// Compara por apellidos, nombre y dni

public int compareTo(Object o) {
        Persona persona = (Persona)o;       
        return this.dni.compareTo(persona.dni);
           
}                          
// Compara sólo por el dni



Una vez que tuviéramos una lista con datos, en este caso Personas, la ordenaríamos con la clase java.util.Collections, de la siguiente forma:

Collections.sort(lista);   


Este método puede ordenar cualquier colección que implemente el interface java.util.List, según el orden que indica el método comparteTo.


Ordenación de listas y colecciones mediante la interfaz Comparator

Ordenación de listas (vectores)

 Si lo que se quieren ordenar son listas (vectores), la forma más sencilla es mediante el métodos estáticos sort de la clase Arrays. Para listas de tipos atómicos se puede hacer directamente. Ejemplo:

int listaEnteros [] = {2, 1, 5, 6, 8, 3, 56, 42};

Arrays.sort(listaEnteros);

De igual forma se podría hacer si los elementos son de tipo referencia, como podrían ser String, StringBuilder o elementos de las clases Envoltorio (wrapper). Ejemplo:

String listaStrings [] = {“Ana”, “Pablo”, “Marcos”, “Rosa”, “Lucas”, “Sara”, “Marta”, “Pedro”};

Arrays.sort(listaStrings);


Por último, también se podría hacer para listas de objetos que tengan una clase comparador que implemente la interfaz comparator (y que por tanto defina cómo se comparan dos objetos de tipo Persona). Supongamos que la clase ComparadorPersona, implementa comparator. Se utilizaría así:

public class ComparadorPersona implements Comparator<Persona>{

    @Override

    public int compare(Persona o1, Persona o2) {

        return o1.getApellido1().compareToIgnoreCase(o2.getApellido1());        

    }

}

Persona listaPersonas [] = new Persona[50];

Arrays.sort(listaPersonas, new ComparadorPersona());  //compara por el primer apellido

En lugar de utilizar un comparador propio se podría utilizar el método comparing de la interfaz Comparator. De esta forma:

Comparator<Persona> cp= Comparator.comparing(Persona::getApellido2);

Arrays.sort(listaPersonas, cp);                      //compara por el segundo apellido

Se pueden incluso encadenar los campos por los que comparar. En el siguiente ejemplo se compara por el primer apellido, por el segundo y por el nombre.

Comparator<Persona> cp2= Comparator.comparing(Persona::getApellido1).              thenComparing(Persona::getApellido2).thenComparing(Persona::getNombre);

Arrays.sort(listaPersonas, cp2);

 

También se puede hacer que la comparación sea en orden descendente:

Comparator<Persona> cp3= Comparator.comparing(Persona::getApellido1).reversed();

Arrays.sort(listaPersonas, cp3); //compara por el primer apellido en orden descendente


Ordenación de colecciones

La ventaja que presenta la interfaz Comparator, es que permite ordenar colecciones por distintos campos en diferentes momentos. La solución es crear distintas clases que implementen la interfaz Comparator, cada una que ordene de forma distinta, para después poder usarlas cuando convenga. Después podremos utilizar Collections.sort(), pero pasándole como segundo argumento un comparador.

import java.util.Comparator;                        // CompFichaDni.java

public class CompFichaDni implements Comparator<Ficha>{

     @Override

    public int compare(Ficha o1, Ficha o2){

        return o1.getDni().compareTo(o2.getDni());

}

}


import java.util.Comparator;                        // CompFichaNota.java

public class CompFichaNota implements Comparator<Ficha>{

     @Override

    public int compare(Ficha o1, Ficha o2){

        return (o1.getNota()>o2.getNota() ? 1  : o1.getNota()==o2.getNota() ? 0 :-1);

}

}

 

Después se utilizaría de esta forma:

System.out.println("\n Ordenados por dni:");

 Collections.sort(lista, new CompFichaDni());

 …       

 System.out.println("\n Ordenados por nota:");

Collections.sort(lista, new CompFichaNota());


En lugar de crear una clase que implemente la interfaz, también se pueden crear comparadores directamente a partir de la interfaz y de los métodos de acceso. Supongamos una colección de personas que queremos ordenar por distintos atributos. Ejemplo:

Comparator<Persona> compPers1= Comparator.comparing(Persona::getApellido1);

Comparator<Persona> compPers2= Comparator.comparing(Persona::getNombre);

Comparator<Persona> compPers3= Comparator.comparing(Persona::getApellido1).                thenComparing(Persona::getApellido2).thenComparing(Persona::getNombre);

 

Collections.sort(coleccionPersonas, compPers1);   //compara por el primer apellido

Collections.sort(coleccionPersonas, compPers2);   //compara por el nombre

Collections.sort(coleccionPersonas, compPers3);  

//compara por el primer apellido, el segundo y el nombre

 

 

No hay comentarios:

Publicar un comentario