Comparator, sortare colecții - 1

"Bună, Amigo!"

— Bună, Bilaabo!

„Astăzi vom examina un subiect mic, dar interesant și util: sortarea colecțiilor”.

"Sortarea? Am auzit ceva despre asta."

„Cu mult timp în urmă, fiecare programator trebuia să fie capabil să scrie algoritmi de sortare. A fost capabil și a trebuit să-i scrie. Dar acele zile s-au terminat. Astăzi, scrierea propriului cod de sortare este considerată o formă proastă, la fel ca a rescrie orice altceva care a avut deja fost inventat.”

„În Java (și în alte limbaje de programare), sortarea este deja implementată.  Sarcina ta este să înveți cum să folosești corect ceea ce există deja.

"BINE."

„ Clasa de ajutor Colecții are o metodă de sortare statică care este folosită pentru a sorta colecțiile – sau mai precis, liste. Elementele din Hărți și Seturi nu au o ordine/index, așa că nu există nimic de sortat.”

"Da, îmi amintesc. Am folosit această metodă o dată pentru a sorta o listă de numere."

"Genial. Dar această metodă este mult mai puternică decât pare la prima vedere. Poate sorta nu numai numere, ci și orice obiecte, pe baza oricărui criteriu. Două interfețe ajută metoda să facă acest lucru: Comparabil și Comparator . "

„Uneori trebuie să sortați obiecte, nu numere. De exemplu, să presupunem că aveți o listă de oameni și doriți să le sortați după vârstă. Avem interfața Comparabil pentru asta.”

„Permiteți-mi să vă arăt mai întâi un exemplu și apoi totul va deveni mai clar:”

Exemplu
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;
}
}
Un exemplu despre cum ar putea fi folosit:
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);
}

„Pentru a sorta obiectele, trebuie să știi mai întâi să le compari. Pentru aceasta, folosim Comparable. Interfața Comparable este una generică, ceea ce înseamnă că acceptă un argument de tip. Are o singură metodă generică: compareTo(T o). Această metodă compară obiectul curent (this) și un obiect transmis ca argument (o). Cu alte cuvinte, trebuie să implementăm această metodă în clasa noastră și apoi să o folosim pentru a compara obiectul curent (this) cu obiectul transmis. "

„Și cum funcționează comparTo? Mă așteptam să returneze adevărat sau fals, în funcție de faptul dacă obiectul trecut a fost mai mare sau mai mic.”

„Lucrurile sunt mai complicate aici. Metoda compareTo nu returnează true/false. În schimb, returnează un int. Acest lucru se face de fapt pentru simplitate.

„Când un computer trebuie să determine dacă un număr este mai mare decât altul, pur și simplu scade al doilea număr din primul și apoi se uită la rezultat. Dacă rezultatul este 0, atunci numerele sunt egale. Dacă rezultatul este mai mic decât zero , atunci al doilea număr este mai mare. Și dacă rezultatul este mai mare decât zero, atunci primul număr este mai mare."

"Aceeași logică se aplică aici. Conform specificației, metoda compareTo trebuie să returneze zero dacă obiectele comparate sunt egale. Dacă metoda compareTo returnează un număr mai mare decât zero, atunci obiectul nostru este mai mare decât obiectul trecut. "Dacă compareTo metoda returnează un număr mai mic decât zero, apoi „acest” este mai mic decât obiectul transmis.”

— E puțin ciudat.

„Da, dar dacă comparați obiecte pur și simplu pe baza unor proprietăți numerice, atunci puteți doar să returnați diferența dintre ele scăzând unul din celălalt. Exact așa cum a fost făcut în exemplul de mai sus.”

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

"Cred că înțeleg totul. Dar poate că nu. Dar aproape totul."

„Grozav. Acum să luăm în considerare o problemă mai practică. Să presupunem că ai scris un site web grozav pentru fabricarea de îmbrăcăminte pentru femei în China. Folosiți o clasă Femeie pentru a vă descrie clienții. Ați creat chiar și o pagină web cu un tabel în care le puteți vedea pe toate. . Dar există o problemă…”

„Obiectul Femeia dvs. conține nu numai o vârstă, ci și o mulțime de alte date: prenume, prenume, înălțime, greutate, număr de copii etc.”

"Tabelul de utilizatori are o mulțime de coloane și iată întrebarea: cum vă sortați utilizatorii după diferitele criterii? După greutate, după vârstă, după nume?"

"Hmm. Da, văd adesea tabele care vă permit să sortați după coloană. Deci, cum faceți asta?"

„Pentru aceasta, avem a doua interfață despre care am vrut să vă povestesc astăzi: interfața Comparator. Are și o metodă de comparare, dar necesită două argumente, nu unul: int compare(T o1, T o2). Iată cum se face. lucrări:"

Exemplu
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;
}
}
Un exemplu despre cum ar putea fi folosit:
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);
}

„Interfața Comparator nu ascunde logica de comparare a obiectelor în interiorul clasei obiectelor comparate. În schimb, este implementată într-o clasă separată.”

„Așadar, aș putea face mai multe clase care implementează interfața Comparator și să le pun pe fiecare dintre ele să compare diferite proprietăți? Greutatea într-una, vârsta în alta și înălțimea într-o treime?”

„Da, este foarte simplu și convenabil”.

„Apelăm doar metoda Collections.sort , trecând o listă de obiecte și un alt obiect special ca al doilea argument, care implementează interfața Comparator și vă spune cum să comparați corect perechile de obiecte în procesul de sortare.”

"Hmm. Cred că înțeleg totul. Lasă-mă să încerc. Să zicem că trebuie să sortez utilizatorii după greutate. Ar fi cam așa:"

Exemplu de sortare a utilizatorilor după greutate:
Comparator<Woman> compareByWeight = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.weight - o2.weight;
}
};

Collections.sort(women, compareByWeight);

— Da, exact.

— Grozav. Dar dacă vreau să sortez în ordine inversă?

"Gândește-te la asta. Răspunsul este foarte simplu!"

"Am înțeles! Cam așa:"

Sortare în ordine crescătoare:
return o1.weight - o2.weight;
Sortare în ordine descrescătoare:
return o2.weight – o1.weight;

— Corect. Bravo.

— Și dacă vreau să sortez după nume de familie? Cum sort șirurile, Bilaabo?

„Clasa String implementează deja metoda compareTo. Trebuie doar să o numiți:”

Exemplu de sortare a utilizatorilor după nume:
Comparator<Woman> compareByName = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.name.compareTo(o2.name);
}
};

Collections.sort(women, compareByName);

"A fost o lecție grozavă, Bilaabo. Mulțumesc foarte mult."

— Și îți mulțumesc, prietene!