Clases e interfaces Métodos
java.lang.String int compareTo(String cad) java.util.Arrays static <T> void sort(T[ ] matriz,
Comparator<? Super T> comp) java.util.Comparator<T> int compare(T objA, T objB)
El parámetro de tipo T especifi ca el tipo de datos que se habrá de comparar. En este caso, String se pasará a T.
Comparator defi ne los dos métodos siguientes: int compare(T objA, T objB)
boolean equals(Object obj)
De éstos, sólo compare( ) debe implementarse. El método equals( ) simplemente especifi ca una sobreescritura de equals( ) en Object. La implementación de equals( ) le permite determinar si dos Comparator son iguales. Sin embargo, esta capacidad no siempre es necesaria. Cuando no se necesita (como sucede en este capítulo), no es necesario sobreescribir la implementación de Object.
El método en que estamos interesados es compare( ). Determina la manera en que se compara un objeto con otro. Por lo general, debe devolver menos de cero si objA es menor que objB, más que cero si objA es mayor que objB y cero si los dos objetos son iguales. Al implementar compare( ) de esta manera se logra que opere de acuerdo con el orden natural de los datos. En el caso de cadenas, esto signifi ca orden alfabético. Sin embargo, tiene la libertad de implementar compare( ) para adecuarse a las necesidades de su tarea. Para ordenar a la inversa una matriz de cadenas, necesitará crear una versión de compare( ) que invierta la salida de la comparación.
He aquí la manera de implementar un operador inverso para String. // Crea un Comparator que devuelve la salida
// de una comparación de cadena inversa.
class CompCadInv implements Comparator<String> { // Implementa el método compare( ) de modo que // invierte el orden de la comparación de la cadena. public int compare(String cadA, String cadB) {
// Compara cadB con cadA, en lugar de cadA con cadB. return cadB.compareTo(cadA);
} }
Revisemos de cerca CompCadInv. En primer lugar, observe que implementa Comparator. Esto signifi ca que un objeto de tipo CompCadInv se puede usar en cualquier lugar que se necesite un Comparator. Asimismo, observe que implementa una versión específi ca de String de Comparator. Por tanto, CompCadInv no es, en sí, genérico. Sólo funciona con cadenas.
Ahora, observe que el método compare( ) llama al método compareTo( ) de String para comparar dos cadenas. compareTo( ) es especifi cada por la interfaz Comparable, que está
implementada por String (y muchas otras clases). Una clase que implementa Comparable garantiza que los objetos de esa clase pueden ordenarse. A continuación se muestra la forma general de compareTo( ), como la implementa String:
int compareTo(String cad)
Devuelve menos de cero si la cadena de invocación es menor que cad, más de cero si es mayor que cad y cero si son iguales. Una cadena es menor que otra si se encuentra antes en el orden alfabético y es mayor si se encuentra después.
El método compare( ) de CompCadInv devuelve el resultado de la llamada a compareTo( ). Sin embargo, observe que compare( ) llama a compareTo( ) en orden inverso. Es decir, se llama a compareTo( ) en cadB mientras cadA se pasa como argumento. Para una comparación normal, cadA invocaría a compareTo( ), pasando cadB. Sin embargo, como cadB invoca a compareTo( ), se invierte el resultado de la comparación. Por tanto, se invierte el orden de las dos cadenas.
Una vez que ha creado un comparador inverso, se crea un objeto de ese comparador y se pasa a esta versión de sort( ) defi nida por java.util.Arrays:
static<T> void sort(T[ ] matriz, Comparator<? Super T> comp)
Observe la cláusula super. Asegura que la matriz pasada a sort( ) sea compatible con el tipo de Comparator. Después de la llamada a sort( ), la matriz estará en orden alfabético invertido.
Ejemplo
En el siguiente ejemplo se invierte el orden de una matriz de cadenas. Para fi nes de demostración, también se les ordena de manera natural empleando la versión predeterminada de sort( ).
// Ordena una matriz de cadenas en orden inverso. import java.util.*;
// Crea un Comparator que devuelve la salida // de una comparación de cadena inversa.
class CompCadInv implements Comparator<String> { // Implementa el método compare( ) de modo que // invierte el orden de la comparación de la cadena. public int compare(String cadA, String cadB) {
// Compara cadB con cadA, en lugar de cadA con cadB. return cadB.compareTo(cadA);
} }
// Demuestra el comparador de cadena inverso. class OrdenCadInv {
public static void main(String args[ ]) { // Crea una matriz simple de cadenas.
String cads[ ] = { "perro", "caballo", "cebra", "vaca", "gato" }; // Muestra el orden inicial.
System.out.print("Orden inicial: "); for(String s : cads)
System.out.print(s + " "); System.out.println("\n");
// Ordena la matriz a la inversa.
// Empieza por crear un comparador de cadena inversa. CompCadInv cci = new CompCadInv( );
// Ahora, ordena las cadenas empleando el comparador inverso. Arrays.sort(cads, cci);
// Muestra el orden inverso.
System.out.print("Orden inverso: "); for(String s : cads)
System.out.print(s + " "); System.out.println("\n");
// Para comparación, ordena la cadena de manera natural. Arrays.sort(cads);
// Muestra el orden natural.
System.out.print("Orden natural: "); for(String s : cads) System.out.print(s + " "); System.out.println("\n"); } }
A continuación se muestra la salida de este programa: Orden inicial: perro caballo cebra vaca gato Orden inverso: vaca perro gato cebra caballo Orden natural: caballo cebra gato perro vaca
Opciones
Aunque esta solución ordena cadenas en orden alfabético inverso, la misma técnica básica puede generalizarse para otras situaciones. Por ejemplo, puede revertir el orden de otros tipos de datos al crear el Comparator apropiado. Simplemente adapta el método mostrado en el ejemplo.
El método compareTo( ) defi nido por String es sensible a mayúsculas y minúsculas. Esto signifi ca que ambos tipos de letra se ordenarán por separado. Tiene la opción de ordenar datos sin importar las diferencias entre mayúsculas y minúsculas al emplear compareToIgnoreCase( ). (Consulte Ignore las diferencias entre mayúsculas y minúsculas cuando ordene una matriz de cadenas).
Puede ordenar cadenas con base en alguna subcadena específi ca. Por ejemplo, si cada cadena contiene un nombre y una dirección de correo electrónico, entonces puede crear un comparador que ordene a partir de la parte de la dirección de cada cadena. Una manera de realizar esto consiste en usar el método regionMatches( ). También puede ordenar por algún criterio diferente de una estricta relación alfabética. Por ejemplo, cadenas que representan tareas pendientes pueden ordenarse por prioridad.
En Java, el orden natural de las cadenas es sensible a mayúsculas y minúsculas. Esto signifi ca que las letras mayúsculas están separadas y son diferentes de las minúsculas. Como resultado, cuando ordena una matriz de cadenas, podrían ocurrir algunas sorpresas que no son bienvenidas. Por ejemplo, si ordena una matriz String que contiene las siguientes palabras:
alfa beta Gama Zeta
El orden resultante será como se muestra aquí: Gama Zeta alfa beta
Como verá, aunque Gama y Zeta normalmente se encontrarían después de alfa y beta, están al principio de la matriz ordenada. La razón es que, en Unicode, las mayúsculas están representadas por valores menores que los usados para las minúsculas. Por tanto, aunque Zeta se encontraría normalmente al fi nal de la lista cuando se ordena alfabéticamente, se encuentra antes de alfa cuando son importantes las diferencias entre mayúsculas y minúsculas. ¡Esto puede llevar a órdenes que producen resultados técnicamente exactos, pero indeseables!
NOTA Como algo interesante hay que mencionar que una mayúscula vale exactamente 32 menos que su
equivalente en minúsculas. Por ejemplo, el valor de Unicode para la A es 65. Y para la a es 97. Por fortuna, es muy fácil ordenar una matriz de cadenas con base en el verdadero orden alfabético al crear un Comparator que ignore si una letra está en mayúsculas o minúsculas durante el proceso de ordenamiento. La técnica es similar a la descrita en Ordene una matriz de cadenas de manera inversa. Los detalles se describen a continuación.
Paso a paso
Para ignorar las diferencias entre mayúsculas y minúsculas cuando ordene una matriz de cadenas se incluyen estos tres pasos:
1. Cree un Comparator que ignore las diferencias entre mayúsculas y minúsculas de dos