Komparator, sortowanie kolekcji - 1

"Cześć, Amigo!"

"Cześć, Bilaabo!"

„Dzisiaj przyjrzymy się małemu, ale interesującemu i przydatnemu tematowi: sortowaniu kolekcji”.

- Sortowanie? Coś o tym słyszałem.

„Dawno temu każdy programista musiał umieć pisać algorytmy sortujące. Był w stanie i musiał je pisać. Ale te czasy minęły. Dziś pisanie własnego kodu sortującego jest uważane za złą formę, podobnie jak przepisywanie czegokolwiek innego, co już zostało został wynaleziony”.

„W Javie (i innych językach programowania) sortowanie jest już zaimplementowane.  Twoim zadaniem jest nauczyć się właściwie wykorzystywać to, co już istnieje ” .

"OK."

„ Klasa pomocnicza Collections ma statyczną metodę sortowania, która służy do sortowania kolekcji — a dokładniej list. Elementy w mapach i zestawach nie mają kolejności/indeksu, więc nie ma czego sortować”.

„Tak, pamiętam. Kiedyś użyłem tej metody do posortowania listy liczb”.

„Świetnie. Ale ta metoda jest znacznie potężniejsza, niż się wydaje na pierwszy rzut oka. Potrafi sortować nie tylko liczby, ale także dowolne obiekty na podstawie dowolnych kryteriów. Pomagają w tym dwa interfejsy: Porównywalny i Porównywalny .

„Czasami trzeba posortować przedmioty, a nie liczby. Na przykład załóżmy, że masz listę osób i chcesz je posortować według wieku. Mamy do tego interfejs Comparable ”.

„Pozwól, że najpierw pokażę ci przykład, a potem wszystko stanie się jaśniejsze:”

Przykład
public class Woman implements Comparable<Woman>
{
public int age;

public Woman(int age) {
this.age = age;
}

public int compareTo(Woman o)
{
return this.age - o.age;
}
}
Przykład, jak można go wykorzystać:
public static void main(String[] args )
{
ArrayList<Woman> women = new ArrayList<Woman>();
women.add(new Woman(18));
women.add(new Woman(21));
women.add(new Woman(5));

Collections.sort(women);
}

„Aby posortować obiekty, musisz najpierw wiedzieć, jak je porównywać. W tym celu używamy interfejsu Comparable. Interfejs Comparable jest interfejsem ogólnym, co oznacza, że ​​akceptuje argument typu. Ma tylko jedną metodę ogólną: CompareTo(T o). Ta metoda porównuje bieżący obiekt (this) z obiektem przekazanym jako argument (o).Innymi słowy, musimy zaimplementować tę metodę w naszej klasie, a następnie użyć jej do porównania bieżącego obiektu (this) z przekazanym obiektem. "

„A jak działa funkcja CompareTo? Spodziewałem się, że zwróci wartość true lub false w zależności od tego, czy przekazany obiekt był większy, czy mniejszy”.

„Tutaj sprawa jest trudniejsza. Metoda CompareTo nie zwraca true/false. Zamiast tego zwraca int. W rzeczywistości jest to zrobione dla uproszczenia.

„Kiedy komputer musi ustalić, czy jedna liczba jest większa od drugiej, po prostu odejmuje drugą liczbę od pierwszej, a następnie patrzy na wynik. Jeśli wynik wynosi 0, liczby są równe. Jeśli wynik jest mniejszy od zera , to druga liczba jest większa. A jeśli wynik jest większy od zera, to pierwsza liczba jest większa”.

„Tutaj obowiązuje ta sama logika. Zgodnie ze specyfikacją metoda CompareTo musi zwracać zero, jeśli porównywane obiekty są równe. Jeśli metoda CompareTo zwraca liczbę większą od zera, to nasz obiekt jest większy niż przekazany obiekt. metoda zwraca liczbę mniejszą od zera, wtedy „to” jest mniejsze niż przekazany obiekt”.

– To trochę dziwne.

„Tak, ale jeśli porównujesz obiekty po prostu na podstawie jakiejś właściwości liczbowej, możesz po prostu zwrócić różnicę między nimi, odejmując jeden od drugiego. Dokładnie tak, jak to zrobiono w powyższym przykładzie”.

public int compareTo(Woman o)
{
return this.age - o.age;
}

„Myślę, że wszystko rozumiem. Ale może nie. Ale prawie wszystko”.

„Świetnie. Teraz rozważmy bardziej praktyczny problem. Załóżmy, że napisałeś fajną stronę internetową poświęconą szyciu odzieży damskiej w Chinach. Używasz klasy Kobieta do opisywania swoich klientów. Stworzyłeś nawet stronę internetową z tabelą, na której możesz zobaczyć je wszystkie Ale jest problem…”

„Twój obiekt Kobieta zawiera nie tylko wiek, ale także całą masę innych danych: imię, nazwisko, wzrost, wagę, liczbę dzieci itp.”

„Tabela użytkowników ma wiele kolumn i oto pytanie: jak sortujesz użytkowników według różnych kryteriów? Według wagi, wieku, nazwiska?”

„Hmm. Tak, często widzę tabele, które pozwalają sortować według kolumn. Jak to zrobić?”

„W tym celu mamy drugi interfejs, o którym chciałem wam dzisiaj powiedzieć: interfejs Comparator. Posiada również metodę porównania, ale wymaga dwóch argumentów, a nie jednego: int Compare(T o1, T o2). Oto jak to zrobić Pracuje:"

Przykład
public class Woman
{
public int age;
public int childrenCount;
public int weight;
public int height;
public String name;

public Woman(int age) {
this.age = age;
}
}
Przykład, jak można go wykorzystać:
public static void main(String[] args )
{
ArrayList<Woman> women = new ArrayList<Woman>();
women.add(new Woman(18));
women.add(new Woman(21));
women.add(new Woman(5));

Comparator<Woman> compareByHeight = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.height - o2.height;
}
};

Collections.sort(women, compareByHeight);
}

„Interfejs Comparator nie ukrywa logiki porównywania obiektów wewnątrz klasy porównywanych obiektów. Zamiast tego jest zaimplementowany w oddzielnej klasie”.

„Mogę więc stworzyć kilka klas, które implementują interfejs komparatora, i sprawić, by każda z nich porównywała różne właściwości? Waga w jednej, wiek w innej i wzrost w trzeciej?”

„Tak, to bardzo proste i wygodne”.

„Wywołujemy po prostu metodę Collections.sort , przekazując listę obiektów i inny obiekt specjalny jako drugi argument, który implementuje interfejs Comparator i mówi, jak poprawnie porównywać pary obiektów w procesie sortowania”.

„Hmm. Chyba wszystko rozumiem. Spróbuję. Powiedzmy, że muszę posortować użytkowników według wagi. Wyglądałoby to mniej więcej tak:”

Przykład sortowania użytkowników według wagi:
Comparator<Woman> compareByWeight = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.weight - o2.weight;
}
};

Collections.sort(women, compareByWeight);

"Tak, dokładnie."

„Świetnie. Ale co, jeśli chcę posortować w odwrotnej kolejności?”

„Pomyśl o tym. Odpowiedź jest bardzo prosta!”

„Mam to! W ten sposób:”

Sortowanie w porządku rosnącym:
return o1.weight - o2.weight;
Sortowanie w kolejności malejącej:
return o2.weight – o1.weight;

Dobra robota.

„A jeśli chcę sortować według nazwiska? Jak mam sortować ciągi znaków, Bilaabo?”

„Klasa String implementuje już metodę CompareTo. Wystarczy ją wywołać:”

Przykład sortowania użytkowników według nazwy:
Comparator<Woman> compareByName = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.name.compareTo(o2.name);
}
};

Collections.sort(women, compareByName);

"To była świetna lekcja, Bilaabo. Dziękuję bardzo."

— A tobie dziękuję, przyjacielu!