comparador de java, ¿cómo ordenar por número entero?

Estoy tratando de aprender a comparar 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 estén ordenados por edad y en orden descendente para que el mayor sea el primero y el más joven el último?

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() + ", ");
}
}

preguntado el 22 de mayo de 12 a las 21:05

Este ciertamente no es un buen ejemplo, usar un perro para comparar las edades de otros dos es un diseño increíblemente malo. No importa si esto es solo un pequeño ejemplo de cómo esto puede funcionar. Le da a la gente ideas equivocadas sobre cómo implementar correctamente estas interfaces. -

6 Respuestas

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 edad si eso es lo que está buscando.

Actualizar:

@Arian tiene razón en sus comentarios, una de las formas aceptadas de declarar un comparador para un perro sería declararlo como un campo final estático público en la clase misma.

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);
    }

}

Luego, puede usarlo en cualquier parte de su código donde le gustaría comparar perros de la siguiente manera:

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

Otra cosa importante para recordar al implementar Comparable es que es importante que compareTo funcione consistentemente con iguales. Aunque no es obligatorio, no hacerlo podría provocar un comportamiento extraño en algunas colecciones, como algunas implementaciones de Sets. Ver este publique para obtener más información sobre principios sólidos de implementación de compareTo.

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

Update 3: Con Java 8, su Comparador podría escribirse mucho más sucintamente como:

public static final Comparator<Dog> DESCENDING_COMPARATOR = 
    Comparator.comparing(Dog::getDogAge).reversed();

La sintaxis para Collections.sort sigue igual, pero compare Se puede escribir como

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

respondido 23 mar '18, 16:03

Es poco probable que represente un problema aquí, pero este comparador tiene un error de desbordamiento/subdesbordamiento de enteros. Si las edades de los perros son Integer.MIN_VALUE y cualquier entero positivo (o Integer.MAX_VALUE y cualquier número negativo), obtendrá un ajuste y el orden de clasificación será inesperado. Parece una tontería, pero esto es algo en lo que creo que los programadores deberían estar pensando, incluso cuando comparan las edades de los perros. Intenta usar Integer.compare (y otros métodos similares en otros java.lang.Number subclases) en lugar de realizar su propia resta. - cristobal schultz

comentario para la solución Update 3 Java 8: para comparar la edad, debe usar compareInt en lugar de comparar. - Croo

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

contestado el 13 de mayo de 15 a las 09:05

¿Podría elaborar más su respuesta agregando un poco más de descripción sobre la solución que proporciona? - abarisona

Supongo que te refieres Integer.compare(o1.getDogAge(), o2.getDogAge())? La clase Perro de OP no tiene un getAge, y restar ID de la edad no tiene sentido. - SL Barth

este código requería un nivel mínimo de API 19 debido a Integer.compare(o1.getAge(), o2.getId()). Si desea usarlo en niveles de API más bajos, puede usar o1.getAge() - o2.getAge() instade - Stoycho Andreev

mi error, devuelve Integer.compare(o1.getAge(), o2.getAge()); - Jorge Thekkan

Simplemente reemplace:

return d.age - d1.age;

Por:

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

O invertir para invertir la lista:

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

EDIT:

Solucionado el "problema de memoria".
De hecho, la mejor solución es cambiar el age en el campo Dog clase de Integer, porque hay muchos beneficios, como la null posibilidad...

contestado el 22 de mayo de 12 a las 22:05

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

Al menos usa Integer.valueOf() en lugar de new - Cefalópodo

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

Integer.compare en android requiere api >= 19 - jan rabe

Desde Java 8 puedes usar:

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

Respondido 14 Feb 19, 21:02

Una forma sencilla es

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

En una nota al margen, Dog realmente no debería implementar Comparator. Significa que tienes 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 que los comparadores sean clases separadas.

p.ej.

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

Esto tiene el beneficio adicional de que puede usar el nombre de la clase para decir cómo Comparator 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

Tampoco deberías tener Dog implement Comparable. Las Comparable La interfaz se utiliza para indicar que existe una forma inherente y natural de ordenar estos objetos (como números y cadenas). Ahora bien, este no es el caso de los objetos Perro, ya que a veces es posible que desee ordenarlos por edad y, a veces, es posible que desee ordenarlos por nombre.

contestado el 22 de mayo de 12 a las 22:05

Si tiene acceso a la API comparable de Java 8, Comparable.comparingToInt() puede ser de utilidad. (Ver Documentación comparable de Java 8).

Por ejemplo, una Comparator<Dog> para ordenar Dog las instancias descendientes por edad podrían crearse con lo siguiente:

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

La función toma un mapeo lambda T a Integery 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, encontré esta pregunta mientras buscaba 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 en qué terminé decidiéndome.

Respondido 16 ago 16, 00:08

no es Comparable.comparingToInt(), edítelo a Comparator.comparingToInt(...) - swaroop

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.