variable tipos tipo referenciados referencia programacion objetos objeto datos java sorting comparator comparable

tipos - Clasificación de objetos Java usando múltiples claves



variables de referencia en java (7)

Acabo de reescribir tu código sin declaraciones else anidadas. ¿Te gusta ahora?

@Override public int compare(Duck d1, Duck d2){ int weightCmp = d1.weight.compareTo(d2.weight); if (weightCmp != 0) { return weightCmp; } int ageCmp = d1.age.compareTo(d2.age); if (ageCmp != 0) { return ageCmp; } return d1.name.compareTo(d2.age); }

Tengo una colección de objetos Duck y me gustaría ordenarlos usando varias claves .

class Duck { DuckAge age; //implements Comparable DuckWeight weight; //implements Comparable String name; } List<Duck> ducks = Pond.getDucks();

p.ej. Quiero clasificarlos principalmente por su peso , y secundariamente por su edad . Si dos patos tienen exactamente el mismo peso y la misma edad exacta, entonces diferenciémoslos usando sus nombres como clave terciaria . Podría hacer algo como esto:

Collections.sort(ducks, new Comparator<Duck>(){ @Override public int compare(Duck d1, Duck d2){ int weightCmp = d1.weight.compareTo(d2.weight); if (weightCmp != 0) { return weightCmp; } int ageCmp = d1.age.compareTo(d2.age); if (ageCmp != 0) { return ageCmp; } return d1.name.compareTo(d2.name); } });

Bueno, hago esto con bastante frecuencia, pero esta solución no huele bien. No escala bien, y es fácil equivocarse. ¡Seguramente debe haber una forma mejor de clasificar patos usando múltiples llaves! ¿Alguien sabe de una mejor solución?

EDIT elimina else ramas innecesarias


En primer lugar, tu solución no es tan lenta.

Si realmente quieres otro método, dale a cada pato una "puntuación" que es esencialmente un único número que es la suma de sus tres características, pero con una gran ponderación (perdón por el juego de palabras casi ineludible) para el peso, una menor para la edad ; y uno muy pequeño para el nombre.

Puede asignar ~ 10 bits para cada característica, por lo que para cada característica debe estar en el rango 0..1023 .

score = ( (weight << 10) + age) << 10 + name;

Esto es probablemente completamente innecesario, pero sea lo que sea :)



Puede usar CompareToBuilder de Apache Commons Lang . (Explica comparable, pero también funciona para Comparator).


Solución Java 8:

Comparator<Duck> cmp = Comparator.comparing(Duck::getWeight) .thenComparing(Duck::getAge) .thenComparing(Duck::getName);

¡Hurra por lambdas, referencias de métodos y métodos predeterminados :)! Lástima que tengamos que definir getters, o usar lambdas explícitos , así:

Comparator<Duck> cmp = Comparator .comparing((Duck duck)-> duck.weight) .thenComparing((Duck duck)-> duck.age) .thenComparing(duck-> duck.name);

La inferencia de tipo no funcionará con lambdas implícitas, por lo que debe especificar el tipo de argumento de las dos primeras lambdas. Más detalles en esta respuesta por Brian Goetz .


Guava es más elegante:

return ComparisonChain.start() .compare(d1.weight, d2.weight) .compare(d1.age, d2.age) .compare(d1.name, d2.name) .result();

Apache commons-lang tiene una construcción similar, CompareToBuilder .


List<Duck> ducks = new ArrayList<Duck>(); Collections.sort(ducks, new Comparator<Duck>() { @Override public int compare(Duck o1, Duck o2) { return new org.apache.commons.lang.builder.CompareToBuilder(). append(o1.weight, o2.weight). append(o1.age, o2.age). append(o1.name, o2.name). toComparison(); } });