Comparador, clasificación de colecciones - 1

"¡Hola, amigo!"

"¡Hola, Bilaabo!"

"Hoy examinaremos un tema pequeño, pero interesante y útil: la clasificación de colecciones".

"¿Clasificar? Escuché algo sobre eso".

"Hace mucho tiempo, cada programador tenía que ser capaz de escribir algoritmos de ordenación. Podía y tenía que escribirlos. Pero esos días terminaron. Hoy en día, escribir su propio código de ordenación se considera de mala forma, al igual que reescribir cualquier otra cosa que ya se haya hecho". sido inventado".

"En Java (y otros lenguajes de programación), la clasificación ya está implementada.  Su tarea es aprender a usar correctamente lo que ya existe " .

"DE ACUERDO."

"La clase de ayuda Collections tiene un método de clasificación estático que se usa para clasificar colecciones, o más precisamente, listas. Los elementos en Maps and Sets no tienen un orden/índice, por lo que no hay nada que clasificar".

"Sí, lo recuerdo. Usé este método una vez para ordenar una lista de números".

"Genial. Pero este método es mucho más poderoso de lo que parece a primera vista. Puede ordenar no solo números, sino también cualquier objeto, según cualquier criterio. Dos interfaces ayudan al método a hacer esto: Comparable y Comparator " .

"A veces necesita ordenar objetos, no números. Por ejemplo, suponga que tiene una lista de personas y desea ordenarlas por edad. Tenemos la interfaz Comparable para esto".

"Déjame mostrarte primero un ejemplo, y luego todo se aclarará:"

Ejemplo
public class Woman implements Comparable<Woman>
{
public int age;

public Woman(int age) {
this.age = age;
}

public int compareTo(Woman o)
{
return this.age - o.age;
}
}
Un ejemplo de cómo se podría utilizar:
public static void main(String[] args )
{
ArrayList<Woman> women = new ArrayList<Woman>();
women.add(new Woman(18));
women.add(new Woman(21));
women.add(new Woman(5));

Collections.sort(women);
}

"Para ordenar objetos, primero debe saber cómo compararlos. Para esto, usamos Comparable. La interfaz Comparable es genérica, lo que significa que acepta un argumento de tipo. Tiene solo un método genérico: compareTo(T o). Este método compara el objeto actual (this) y un objeto pasado como argumento (o).En otras palabras, necesitamos implementar este método en nuestra clase y luego usarlo para comparar el objeto actual (this) con el objeto pasado. "

"¿Y cómo funciona compareTo? Esperaba que devolviera verdadero o falso dependiendo de si el objeto pasado era mayor o menor".

"Las cosas son más complicadas aquí. El método compareTo no devuelve verdadero/falso. En cambio, devuelve un int. Esto se hace realmente por simplicidad.

"Cuando una computadora necesita determinar si un número es mayor que otro, simplemente resta el segundo número del primero y luego mira el resultado. Si el resultado es 0, entonces los números son iguales. Si el resultado es menor que cero , entonces el segundo número es mayor. Y si el resultado es mayor que cero, entonces el primer número es mayor".

"Aquí se aplica la misma lógica. De acuerdo con la especificación, el método compareTo debe devolver cero si los objetos comparados son iguales. Si el método compareTo devuelve un número mayor que cero, entonces nuestro objeto es mayor que el objeto pasado. "Si el método compareTo El método devuelve un número menor que cero, entonces 'esto' es menor que el objeto pasado".

"Eso es un poco raro".

"Sí, pero si está comparando objetos basándose simplemente en alguna propiedad numérica, entonces puede devolver la diferencia entre ellos restando uno del otro. Tal como se hizo en el ejemplo anterior".

public int compareTo(Woman o)
{
return this.age - o.age;
}

"Creo que entiendo todo. Pero tal vez no. Pero casi todo".

"Genial. Ahora consideremos un problema más práctico. Supongamos que ha escrito un sitio web genial para hacer ropa de mujer en China. Usa una clase Mujer para describir a sus clientes. Incluso creó una página web con una tabla donde puede verlos a todos Pero hay un problema..."

"Su objeto Mujer contiene no solo una edad, sino también una gran cantidad de otros datos: nombre, apellido, altura, peso, número de hijos, etc."

"La tabla de usuarios tiene muchas columnas, y aquí está la pregunta: ¿cómo clasifica a sus usuarios según los distintos criterios? ¿Por peso, por edad, por apellido?"

"Hmm. Sí, a menudo veo tablas que te permiten ordenar por columna. Entonces, ¿cómo haces eso?"

"Para esto, tenemos la segunda interfaz de la que quería hablarles hoy: la interfaz Comparator. También tiene un método de comparación, pero toma dos argumentos, no uno: int compare(T o1, T o2). Así es como funciona obras:"

Ejemplo
public class Woman
{
public int age;
public int childrenCount;
public int weight;
public int height;
public String name;

public Woman(int age) {
this.age = age;
}
}
Un ejemplo de cómo se podría utilizar:
public static void main(String[] args )
{
ArrayList<Woman> women = new ArrayList<Woman>();
women.add(new Woman(18));
women.add(new Woman(21));
women.add(new Woman(5));

Comparator<Woman> compareByHeight = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.height - o2.height;
}
};

Collections.sort(women, compareByHeight);
}

"La interfaz Comparator no oculta la lógica de comparación de objetos dentro de la clase de los objetos que se comparan. En cambio, se implementa en una clase separada".

"Entonces, ¿podría crear varias clases que implementen la interfaz Comparator y hacer que cada una de ellas compare diferentes propiedades? ¿Peso en una, edad en otra y altura en una tercera?"

"Sí, es muy simple y conveniente".

"Simplemente llamamos al método Collections.sort , pasando una lista de objetos y otro objeto especial como segundo argumento, que implementa la interfaz Comparator y le dice cómo comparar correctamente pares de objetos en el proceso de clasificación".

"Hmm. Creo que entiendo todo. Déjame intentarlo. Digamos que necesito clasificar a los usuarios por peso. Sería algo como esto:"

Ejemplo de clasificación de usuarios por peso:
Comparator<Woman> compareByWeight = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.weight - o2.weight;
}
};

Collections.sort(women, compareByWeight);

"Sí exactamente."

"Genial. Pero, ¿y si quiero ordenar en orden inverso?"

"Piénsalo. ¡La respuesta es muy simple!"

"¡Lo tengo! Así:"

Clasificación en orden ascendente:
return o1.weight - o2.weight;
Ordenando en orden decreciente:
return o2.weight – o1.weight;

"Correcto. Bien hecho".

"¿Y si quiero ordenar por apellido? ¿Cómo ordeno las cadenas, Bilaabo?"

"La clase String ya implementa el método compareTo. Solo necesita llamarlo:"

Ejemplo de clasificación de usuarios por nombre:
Comparator<Woman> compareByName = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.name.compareTo(o2.name);
}
};

Collections.sort(women, compareByName);

"Esa fue una gran lección, Bilaabo. Muchas gracias".

"¡Y gracias a ti, mi amigo!"