2012-05-22 15 views
17

Im tratando de aprender comparator en java y encontré este gran ejemplo en línea, mi pregunta es cómo se cambiaría este código para que los nombres de las mascotas se ordenan por edad y en orden descendente para que el más viejo sea el primero y el último sea el último ?comparador de java, ¿cómo ordenar por entero?

class Dog implements Comparator<Dog>, Comparable<Dog>{ 
private String name; 
private int age; 
Dog(){ 
} 

Dog(String n, int a){ 
    name = n; 
    age = a; 
} 

public String getDogName(){ 
    return name; 
} 

public int getDogAge(){ 
    return age; 
} 

// Overriding the compareTo method 
public int compareTo(Dog d){ 
    return (this.name).compareTo(d.name); 
} 

// Overriding the compare method to sort the age 
public int compare(Dog d, Dog d1){ 
    return d.age - d1.age; 
} 
} 

public class Example{ 
public static void main(String args[]){ 
    // Takes a list o Dog objects 
    List<Dog> list = new ArrayList<Dog>(); 

    list.add(new Dog("Shaggy",3)); 
    list.add(new Dog("Lacy",2)); 
    list.add(new Dog("Roger",10)); 
    list.add(new Dog("Tommy",4)); 
    list.add(new Dog("Tammy",1)); 
    Collections.sort(list);// Sorts the array list 

    for(Dog a: list)//printing the sorted list of names 
    System.out.print(a.getDogName() + ", "); 

    // Sorts the array list using comparator 
    Collections.sort(list, new Dog()); 
    System.out.println(" "); 
    for(Dog a: list)//printing the sorted list of ages 
    System.out.print(a.getDogName() +" : "+ 
    a.getDogAge() + ", "); 
} 
} 
+5

Esto ciertamente no es un buen ejemplo, usando un perro para comparar las edades de los otros dos es increíblemente mal diseño. No importa si esto es solo un pequeño ejemplo de cómo puede funcionar esto. Le da a las personas ideas equivocadas sobre cómo implementar estas interfaces correctamente. – Cephalopod

Respuesta

72

simplemente cambiando

public int compare(Dog d, Dog d1) { 
    return d.age - d1.age; 
} 

a

public int compare(Dog d, Dog d1) { 
    return d1.age - d.age; 
} 

debe ordenarlos en el orden inverso de la edad si eso es lo que busca.

Actualización:

@Arian es justo en sus comentarios, una de las formas aceptadas de declarar un comparador para un perro sería donde se declara como un campo public static final en la propia clase.

class Dog implements Comparable<Dog> { 
    private String name; 
    private int age; 

    public static final Comparator<Dog> DESCENDING_COMPARATOR = new Comparator<Dog>() { 
     // Overriding the compare method to sort the age 
     public int compare(Dog d, Dog d1) { 
      return d.age - d1.age; 
     } 
    }; 

    Dog(String n, int a) { 
     name = n; 
     age = a; 
    } 

    public String getDogName() { 
     return name; 
    } 

    public int getDogAge() { 
     return age; 
    } 

    // Overriding the compareTo method 
    public int compareTo(Dog d) { 
     return (this.name).compareTo(d.name); 
    } 

} 

A continuación, puede utilizarlo en cualquier lugar de su código en el que desea comparar los perros de la siguiente manera:

// Sorts the array list using comparator 
Collections.sort(list, Dog.DESCENDING_COMPARATOR); 

Otra cosa importante para recordar la hora de implementar Comparable es que es importante que compareTo realiza consistentemente con iguales. Aunque no es necesario, si no lo hace, podría producirse un comportamiento extraño en algunas colecciones, como algunas implementaciones de Conjuntos. Consulte la publicación this para obtener más información sobre los principios de implementación de compareTo.

Actualización 2: Chris tiene razón, este código es susceptible de desbordamientos para grandes valores negativos de edad. La forma correcta de implementar esto en Java 7 y superiores sería Integer.compare(d.age, d1.age) en lugar de d.age - d1.age.

+3

Es poco probable que represente un problema, pero este comparador tiene un error de desbordamiento/subdesbordamiento de número entero. Si las edades de los perros son 'Integer.MIN_VALUE' y cualquier entero positivo (o' Integer.MAX_VALUE' y cualquier número negativo), te darás vuelta y el orden de clasificación será inesperado. Parece una tontería, pero creo que los programadores deberían pensar en esto, incluso cuando se comparan las edades de los perros. Intenta usar 'Integer.compare' (y otros métodos similares en otras subclases' java.lang.Number') en lugar de realizar tu propia resta. –

18

basta con sustituir:

return d.age - d1.age; 

Por:

return ((Integer)d.age).compareTo(d1.age); 

o invertir para revertir la lista:

return ((Integer)d1.age).compareTo(d.age); 

EDIT:

Se corrigió el "problema de memoria".
De hecho, la mejor solución es cambiar el campo age en la clase Dog a Integer, porque hay muchas ventajas, como la posibilidad null ...

+3

A costa de crear innecesariamente objetos. No haga esto para grandes conjuntos de datos cuando tenga que ordenar mucho. En particular, dado que la alternativa es mucho más simple ... –

+1

Al menos use 'Integer.valueOf()' en vez de 'new' – Cephalopod

+4

¿Por qué no simplemente usa' return Integer.compare (d.age, d1.age); '? Está disponible desde Java 7 – McIntosh

4

Una forma sencilla es

Comparator<Dog> ageAscendingComp = ...; 
Comparator<Dog> ageDescendingComp = Collections.reverseOrder(ageAscendingComp); 
// then call the sort method 

En una nota , Perro realmente no debería implementar Comparator.Significa que tiene que hacer cosas extrañas como

Collections.sort(myList, new Dog("Rex", 4)); 
// ^-- why is a new dog being made? What are we even sorting by?! 
Collections.sort(myList, myList.get(0)); 
// ^-- or perhaps more confusingly 

Más bien debe hacer los compartimentos como clases separadas.

por ejemplo.

public class DogAgeComparator implments Comparator<Dog> { 
    public int compareTo(Dog d1, Dog d2) { 
     return d1.getAge() - d2.getAge(); 
    } 
} 

Esto tiene la ventaja añadida de que puede usar el nombre de la clase para decir cómo el Comparador ordenará la lista. p.ej.

Collections.sort(someDogs, new DogNameComparator()); 
// now in name ascending order 

Collections.sort(someDogs, Collections.reverseOrder(new DogAgeComparator())); 
// now in age descending order 

Debe tampoco no tienen perro implementar Comparable. La interfaz Comparable se utiliza para indicar que existe una forma inherente y natural de pedir estos objetos (como números y cadenas). Ahora bien, este no es el caso de los objetos de perro, ya que a veces es posible que desee ordenar por edad y, a veces, puede ordenar por nombre.

11
public class DogAgeComparator implements Comparator<Dog> { 
    public int compare(Dog o1, Dog o2) { 
     return Integer.compare(o1.getAge(), o2.getId()); 
    } 
} 
+3

¿Podría por favor elaborar más su respuesta agregando un poco más de descripción acerca de la solución que proporciona? – abarisone

+2

Supongo que quiere decir 'Integer.compare (o1.getDogAge(), o2.getDogAge())'? La clase Dog de OP no tiene un 'getAge', y restar ID de edad no tiene sentido. –

+3

este código requiere un nivel de API mínimo de 19 debido a Integer.compare (o1.getAge(), o2.getId()). Si desea usarlo en niveles inferiores de API, puede usar o1.getAge() - o2.getAge() instade – Sniper

1

Si tiene acceso a la API de Java comparable 8, Comparable.comparingToInt() pueden ser de utilidad. (Ver Java 8 Comparable Documentation).

Por ejemplo, un Comparator<Dog> para ordenar Dog casos descendente por edad se podrían crear con lo siguiente:

Comparable.comparingToInt(Dog::getDogAge).reversed();

La función de tomar un mapeo lambda T-Integer, y crea un comparador ascendente. La función encadenada .reversed() convierte el comparador ascendente en un comparador descendente.

Nota: si bien esto puede no ser útil para la mayoría de las versiones de Android, me encontré con esta pregunta al buscar información similar para una aplicación Java que no es de Android. Pensé que podría ser útil para otros en el mismo lugar para ver a qué terminé quedándome.

4

Con Java 8 se puede utilizar:

Comparator.comparingInt(Dog::getDogAge).reversed(); 
Cuestiones relacionadas