Mam tablicę obiektów person (int age; String name;)
.
Jak mogę posortować tę tablicę alfabetycznie według nazwy, a następnie według wieku?
Którego algorytmu użyłbyś do tego?
Możesz użyć Collections.sort
w następujący sposób:
private static void order(List<Person> persons) {
Collections.sort(persons, new Comparator() {
public int compare(Object o1, Object o2) {
String x1 = ((Person) o1).getName();
String x2 = ((Person) o2).getName();
int sComp = x1.compareTo(x2);
if (sComp != 0) {
return sComp;
}
Integer x1 = ((Person) o1).getAge();
Integer x2 = ((Person) o2).getAge();
return x1.compareTo(x2);
}});
}
List<Persons>
jest teraz posortowane według nazwy, a następnie według wieku.
String.compareTo
„Porównuje leksykograficznie dwa ciągi znaków” - z dokumentacji .
Collections.sort
jest metodą statyczną w natywnej bibliotece kolekcji. Dokonuje rzeczywistego sortowania, wystarczy dostarczyć komparator, który definiuje sposób porównywania dwóch elementów na liście: osiąga się to poprzez dostarczenie własnej implementacji compare
metody.
Comparator
aby uniknąć konieczności rzutowania danych wejściowych.Comparable
. Zobacz odpowiedź: @ berry120Comparator<Person> comparator = Comparator.comparing(Person::getName).thenComparingInt(Person::getAge);
Dla tych, którzy potrafią korzystać z API strumieniowego Java 8, istnieje lepsze podejście, które jest dobrze udokumentowane tutaj: Lambdy i sortowanie
Szukałem odpowiednika C # LINQ:
Znalazłem mechanizm w Javie 8 w Komparatorze:
Oto fragment, który demonstruje algorytm.
Sprawdź powyższy link, aby uzyskać ładniejszy sposób i wyjaśnienie, w jaki sposób wnioskowanie o typie w Javie sprawia, że definiowanie jest nieco bardziej niezgrabne w porównaniu z LINQ.
Oto pełny test jednostkowy w celach informacyjnych:
źródło
Comparator<Person> comparator = Comparator.comparing(Person::getName).thenComparing(Person::getAge);
thenComparingInt
dla wieku (int)Collections.sort(people, comparator);
zamiast tego?Korzystanie z podejścia strumieniowego Java 8 ...
A podejście Java 8 Lambda ...
W końcu...
źródło
Musisz zaimplementować własny
Comparator
, a następnie z niego skorzystać: na przykładTwój komparator może wyglądać trochę tak:
Komparator najpierw porównuje nazwiska, jeśli nie są one równe, zwraca wynik z porównania, w przeciwnym razie zwraca wynik porównania, porównując wiek obu osób.
Ten kod jest tylko szkicem: ponieważ klasa jest niezmienna, możesz pomyśleć o zbudowaniu jej singletona, zamiast tworzyć nową instancję dla każdego sortowania.
źródło
Aby to osiągnąć, możesz użyć podejścia Java 8 Lambda. Lubię to:
źródło
Zaimplementuj klasę osoby,
Comparable<Person>
a następnie zaimplementuj metodę compareTo, na przykład:To posortuje najpierw według nazwy (bez rozróżniania wielkości liter), a następnie według wieku. Następnie możesz uruchomić
Arrays.sort()
lubCollections.sort()
na kolekcji lub tablicy obiektów Person.źródło
Guawa
ComparisonChain
zapewnia czysty sposób na zrobienie tego. Skorzystaj z tego łącza .Narzędzie do wykonywania łańcuchowej instrukcji porównawczej. Na przykład:
źródło
Możesz zrobić tak:
źródło
Zastosowanie
Comparator
, a następnie umieścić przedmiotów doCollection
, a następnieCollections.sort();
źródło
Utwórz tyle komparatorów, ile potrzeba. Następnie wywołaj metodę „thenComparing” dla każdej kategorii zamówienia. To sposób na zrobienie przez strumienie. Widzieć:
Wygląd: sortowanie obiektu zdefiniowanego przez użytkownika w wielu polach - komparator (strumień lambda)
źródło
Byłbym ostrożny przy używaniu guawy,
ComparisonChain
ponieważ tworzy jej instancję dla każdego elementu, więc patrzyłbyś na tworzenieN x Log N
łańcuchów porównawczych tylko po to, aby porównać, jeśli sortujesz, lubN
instancje, jeśli iterujesz i sprawdzasz pod kątem równości.Zamiast tego utworzyłbym statyczny
Comparator
przy użyciu najnowszego API Java 8, jeśli to możliwe lubOrdering
API Guavy, które pozwala to zrobić, oto przykład z Javą 8:Oto jak korzystać z
Ordering
API Guavy : https://github.com/google/guava/wiki/OrderingExplainedźródło
compare
metody nie tworzy niczego, ale zwraca jedną z pojedynczych przypadkachLESS
,GREATER
lubACTIVE
w zależności od wyniku porównania. Jest to wysoce zoptymalizowane podejście i nie powoduje zwiększenia ilości pamięci ani narzutu wydajności.Lub możesz wykorzystać fakt, że
Collections.sort()
(lubArrays.sort()
) jest stabilny (nie zmienia kolejności elementów, które są równe) i użyćComparator
najpierw do sortowania według wieku, a następnie innego do sortowania według nazwy.W tym konkretnym przypadku nie jest to dobry pomysł, ale jeśli musisz mieć możliwość zmiany kolejności sortowania w czasie wykonywania, może to być przydatne.
źródło
Możesz użyć ogólnego Komparatora szeregowego do sortowania kolekcji według wielu pól.
źródło
Zaktualizowana wersja:
źródło
W przypadku takiej klasy
Book
:sortowanie klasy głównej za pomocą pozorowanych obiektów
źródło
Nie jestem pewien, czy pisanie compartor wewnątrz klasy Person jest w tym przypadku brzydkie. Czy to tak:
źródło