Sortowanie obiektów Java przy użyciu wielu kluczy
Mam kolekcję obiektów kaczych i chciałbym posortować je za pomocą wielu klawiszy .
class Duck {
DuckAge age; //implements Comparable
DuckWeight weight; //implements Comparable
String name;
}
List<Duck> ducks = Pond.getDucks();
Np. Chcę je posortować przede wszystkim według ich wagi , a Po drugie według ich wieku . Jeśli dwie kaczki mają dokładnie taką samą wagę i ten sam wiek, to rozróżnijmy je używając ich nazw jako klucz trzeciorzędowy . Mogę zrobić coś takiego:
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);
}
});
Cóż, robię to dość często, ale to rozwiązanie nie pachnie racja. Nie skaluje się zbyt dobrze i łatwo się zepsuć. Na pewno musi być lepszy sposób sortowania kaczek za pomocą wielu klawiszy! Czy ktoś zna lepsze rozwiązanie?
Edytuj Usunięto niepotrzebne else
gałęzie
7 answers
Guawa jest bardziej elegancka:
return ComparisonChain.start()
.compare(d1.weight, d2.weight)
.compare(d1.age, d2.age)
.compare(d1.name, d2.name)
.result();
Apache commons-lang ma podobną konstrukcję, CompareToBuilder
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-15 21:42:07
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();
}
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-07 12:30:46
Java 8 rozwiązanie:
Comparator<Duck> cmp = Comparator.comparing(Duck::getWeight)
.thenComparing(Duck::getAge)
.thenComparing(Duck::getName);
Hura dla Lambda, referencji metod i domyślnych metod:)! Szkoda, że musimy zdefiniować gettery, lub użyć explicit lambda , w ten sposób:
Comparator<Duck> cmp = Comparator
.comparing((Duck duck)-> duck.weight)
.thenComparing((Duck duck)-> duck.age)
.thenComparing(duck-> duck.name);
Wnioskowanie typu nie będzie działać z domyślnymi lambdami, więc musisz podać typ argumentu dwóch pierwszych lambd. Więcej szczegółów w ta odpowiedź Brian Goetz .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:32
Po pierwsze, twoje rozwiązanie nie jestże powolne.
Jeśli naprawdę chcesz innej metody, to daj każdej kaczce "wynik" , który jest zasadniczo pojedynczą liczbą, która jest sumą ich trzech cech, ale z ogromną wagą (wybacz prawie nieunikniony kalambur) dla wagi, mniejszą dla wieku; i bardzo małą dla nazwy.
Możesz przydzielić ~10 bitów dla każdej charakterystyki, więc dla każdej charakterystyki musisz być w zakresie 0..1023
.
score = ( (weight << 10) + age) << 10 + name;
To jest prawdopodobnie zupełnie niepotrzebne, ale co tam:)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-03 14:04:38
Możesz użyć CompareToBuilder z Apache Commons Lang . (Wyjaśnia porównywalne, ale działa również w przypadku komparatora).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-07 12:26:24
Możesz użyć chained BeanComparators
z Commons BeanUtils:
Comparator comparator = new BeanComparator("weight", new BeanComparator("age"));
Http://commons.apache.org/beanutils/v1.8.3/apidocs/org/apache/commons/beanutils/BeanComparator.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-07 12:28:10
Właśnie przepisałem Twój kod bez zagnieżdżonych instrukcji else. Podoba Ci się teraz?
@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);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-07 12:29:14