sábado, 11 de febrero de 2012

Comparable en Java

votar
   En la entrada anterior, vimos el uso de Comparator en Java. En ésta nos vamos a centrar en el uso de Comparable. Comparable es una interfaz que sólo contiene un método: compareTo, que nos sirve para ordenar los valores según un orden natural, bien sea numérico o alfabético. Si en Comparator debíamos especificar que tipo de comparación queríamos, y proporcionar un comparator, en este caso vemos que eso no es necesario.

   Lo veremos más claro con un ejemplo, y para eso cogeremos el mismo de la pasada entrada, donde teníamos tres alumnos con sus respectivas notas. Vamos a ordenarlo primero de forma alfabética. Pero antes de nada, un pequeño inciso para principiantes: el método compareTo devuelve un int, que puede ser 1, -1 o 0; da igual que estés comparando nombres. 

   Bien, lo primero que hay que hacer es, por supuesto, implementar la interfaz Comparable, y después sobreescribir el método compareTo, como muestra el ejemplo:

import java.util.*;
public class Alumnos2 implements Comparable <Alumnos2>{//usamos genéricos 
   private int nota;                                                                   
   private String nombre;
   public Alumnos2(int nota, String nombre){//muestra del uso de un constructor
   super( );
   this.nota = nota;
   this.nombre = nombre;
   }
   public void setNota(int nota){//muestra del uso de getters y setters
      this.nota = nota;
   }
   public int getNota( ){
      return nota;
   }
   public void setNombre(String nombre){
      this.nombre = nombre;
   }
   public String getNombre( ){
      return nombre;
   }
   public String toString( ){//adecuamos el resultado de compareTo a nuestras necesidades              
      return String.format("Nombre:%s,  Nota:%s", nombre, nota);
   }
   public int compareTo(Alumnos2 a){
      return nombre.compareTo(a.nombre);
   }
   public static void main(String[ ] args){
      Set <Alumnos2> a = new TreeSet <Alumnos2>( );//añadimos los valores
      a.add(new Alumnos2(8, "Ana"));
      a.add(new Alumnos2(6, "Xose"));
      a.add(new Alumnos2(3, "Carlos"));
      System.out.println(a);
   }
}

   El resultado sería el siguiente:
   [Nombre:Ana, Nota:8, Nombre:Carlos, Nota:3, Nombre:Xose, Nota:6]
   
   Fijaos en el uso del método toString( ). Probad a omitirlo y veréis que el resultado cambia a una serie de extraños números: el hashcode.


 Ya tenemos nuestro ejemplo ordenado alfabéticamente. Pero, ¿y si queremos ordenarlo según las notas de cada alumno?. Entonces lo único que tendremos que hacer es cambiar el método compareTo de la siguiente manera: 


   public int compareTo(Alumnos2 a){
      return this.nota - a.nota;
   }


   De esta forma la salida sería:
 [Nombre:Carlos, Nota:3, Nombre:Xose, Nota:6, Nombre:Ana, Nota:8]


   Si lo que queremos son las notas de mayor a menor, bastaría con hacer esto: 
      return a.nota - this.nota;


   El método compareTo debe seguir un contrato, o "reglas", similares a las del método equals( ), que son las siguientes: 
   Tomando sgn(expresión) donde sgn devuelve -1, 0 o 1, según el valor de la expresión sea negativo, cero o positivo, y con explicaciones para los que no sean de ciencias

  •    sgn(x.compareTo(y)) == -sgn(y.compareTo(x)). Si el primer objeto es menor que el segundo, el segundo debe ser más grande que el primero, y al revés. Y si el primero es igual al segundo, el segundo es igual al primero.
  •    (x.compareTo(y)>0 && y.compareTo(z)>0) implica que x.compareTo(z)>0. Si un objeto es más grande que un segundo objeto, y éste es más grande que un tercero, entonces el primero es más grande que el tercero.
  •    x.compareTo(y) == 0 implica que sgn(x.compareTo(z)) == sgn(y.compareTo(z)). Todos los objetos que son iguales al compararlos deben dar el mismo resultado al compararlos con un tercer objeto.

   Y esto es todo. Si queréis ampliar conocimientos podéis leer el libro de Joshua Bloch "Effective Java". Y no olvidéis visitar nuestra web Java Para Nulos ; )

   

sábado, 4 de febrero de 2012

Comparator en Java

votar
   A veces en tu programa necesitas comparar varios elementos, por ejemplo para ordenarlos. En Java hay diversas formas de hacer esto, como usando Comparable, que ordena los elementos según su orden natural (de menor a mayor o alfabéticamente) o usando Comparator, en el que tú especificas la forma en la que quieres que sean ordenados.


   Hoy vamos a ver este último método con un ejemplo muy sencillo. Vamos a usar un array de alumnos y lo vamos a ordenar según sus notas y sus nombres. Podríamos hacerlo con cualquier tipo de colecciones y genéricos, y también simplificarlo para que el código fuese más corto, pero hemos decidido hacerlo así para que podáis ver bien todo el proceso. Notad también que igualmente podríamos haber utilizado Comparable en este código.



import java.util.*;
class Alumnos{
   private int nota;
   private String nombre;
   public void setNota(int nota){
      this.nota = nota;
   }
   public int getNota( ){
      return this.nota;
   }
   public void setNombre(String nombre){
      this.nombre = nombre;
   }
   public String getNombre( ){
      return this.nombre;
   }
}
class ComparaNota implements Comparator{/**hay que implementar la interfazComparator y definir el método compare()*/
   public int compare (Object alum1, Object alum2){
      int alum1Nota = ((Alumnos)alum1).getNota( );//hacemos un casting
      int alum2Nota = ((Alumnos)alum2).getNota( );
      if(alum1Nota > alum2Nota){//ordenamos de mayor a menor
         return -1;
      }else if(alum1Nota < alum2Nota){
         return 1;
      }else{
         return 0;
      }
   }
}
class ComparaNombre implements Comparator{
   public int compare(Object alum1, Object alum2){
      String alum1Nombre = ((Alumnos) alum1).getNombre( );
      String alum2Nombre = ((Alumnos) alum2).getNombre( );
      return alum1Nombre.compareTo(alum2Nombre);/**usamos el método compareTo para un orden  alfabético*/         
   }
}
public class EjemploComparatorJava{//creamos el array y le añadimos valores
   public static void main(String[ ] args){
      Alumnos alumnos[ ] = new Alumnos[3];
      alumnos[0] = new Alumnos( );
      alumnos[0].setNota(8);
      alumnos[0].setNombre("Ana");
      alumnos[1] = new Alumnos( );
      alumnos[1].setNota(6);
      alumnos[1].setNombre("Xose");
      alumnos[2] = new Alumnos( );
      alumnos[2].setNota(3);
      alumnos[2].setNombre("Carlos");
      System.out.println("Alumnos desordenados");
      for(int i = 0; i<alumnos.length;i++){
         System.out.println("Alumno "+(i+1)+" Nombre: "+alumnos[i].getNombre( )+" Nota: "+alumnos[i].getNota( ));
      }
      Arrays.sort(alumnos, new ComparaNota( ));/**usamos el método sort para ordenar las notas*/
      System.out.println("Alumnos ordenados por notas");
      for(int i = 0; i<alumnos.length; i++){
         System.out.println("Alumno "+(i+1)+" Nombre: "+alumnos[i].getNombre( )+" Nota: "+alumnos[i].getNota( ));
      }
      Arrays.sort(alumnos, new ComparaNombre( ));/**ahora ordenamos los nombres*/
      System.out.println("Alumnos ordenados por nombre");
      for(int i = 0;i<alumnos.length; i++){
         System.out.println("Alumno "+(i+1)+" Nombre:     "+alumnos[i].getNombre( )+" Nota: "+alumnos[i].getNota( ));
      }
   }
}



   La salida será como sigue:


Alumnos desordenados
Alumno 1 Nombre: Ana Nota: 8
Alumno 2 Nombre: Xose Nota: 6
Alumno 3 Nombre: Carlos Nota: 3
Alumnos ordenados por notas
Alumno 1 Nombre: Ana Nota: 8
Alumno 2 Nombre: Xose Nota: 6
Alumno 3 Nombre: Carlos Nota: 3
Alumnos ordenados por nombres
Alumno 1 Nombre: Ana Nota: 8
Alumno 2 Nombre: Carlos Nota: 3
Alumno 3 Nombre: Xose Nota: 6


   Si al ordenarlos por notas hubiésemos decidido hacerlo de menor a mayor (basta con cambiar el signo de los unos) el orden hubiese sido Carlos, Xose, Ana.


   Os animamos a que practiquéis con este código, probando con distintas variantes, para que veáis que es muy sencillo.