Komparator, sortering av samlingar - 1

"Hej, Amigo!"

"Hej, Bilaabo!"

"Idag ska vi undersöka ett litet, men intressant och användbart ämne: sortering av samlingar."

"Sortera? Jag har hört något om det."

"Länge sedan var varje programmerare tvungen att skriva sorteringsalgoritmer. Kunde och var tvungen att skriva dem. Men den tiden är över. Idag anses skriva din egen sorteringskod som dålig form, precis som att skriva om allt annat som redan har uppfunnits."

"I Java (och andra programmeringsspråk) är sortering redan implementerad.  Din uppgift är att lära dig hur man korrekt använder det som redan finns. "

"OK."

" Hjälpklassen Samlingar har en statisk sorteringsmetod som används för att sortera samlingar – eller mer exakt, listor. Element i kartor och uppsättningar har ingen ordning/index, så det finns inget att sortera."

"Ja, jag kommer ihåg. Jag använde den här metoden en gång för att sortera en lista med siffror."

"Utmärkt. Men den här metoden är mycket kraftfullare än den verkar vid första anblicken. Den kan sortera inte bara siffror, utan också alla objekt, baserat på vilka kriterier som helst. Två gränssnitt hjälper metoden att göra detta: Comparable och Comparator . "

"Ibland behöver du sortera objekt, inte siffror. Anta till exempel att du har en lista med personer och att du vill sortera dem efter ålder. Vi har det jämförbara gränssnittet för detta."

"Låt mig först visa dig ett exempel, och sedan blir allt tydligare:"

Exempel
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;
}
}
Ett exempel på hur det kan användas:
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);
}

"För att sortera objekt måste du först veta hur du jämför dem. För detta använder vi Comparable. Det jämförbara gränssnittet är ett generiskt, vilket betyder att det accepterar ett typargument. Det har bara en generisk metod: compareTo(T o). Den här metoden jämför det aktuella objektet (detta) och ett objekt som skickas som ett argument (o). Med andra ord måste vi implementera denna metod i vår klass och sedan använda den för att jämföra det aktuella objektet (detta) med det skickade objektet. "

"Och hur fungerar compareTo? Jag förväntade mig att det skulle returnera sant eller falskt beroende på om det passerade objektet var större eller mindre."

"Det är knepigare här. CompareTo-metoden returnerar inte sant/falskt. Istället returnerar den en int. Detta görs faktiskt för enkelhetens skull.

"När en dator behöver avgöra om ett tal är större än ett annat, subtraherar den helt enkelt det andra talet från det första och tittar sedan på resultatet. Om resultatet är 0, så är siffrorna lika. Om resultatet är mindre än noll , då är det andra talet större. Och om resultatet är större än noll, är det första talet större."

"Samma logik gäller här. Enligt specifikationen måste compareTo-metoden returnera noll om de jämförda objekten är lika. Om compareTo-metoden returnerar ett tal större än noll, så är vårt objekt större än det godkända objektet. "Om compareTo metod returnerar ett tal mindre än noll, då är 'detta' mindre än det skickade objektet."

"Det är lite konstigt."

"Ja, men om du jämför objekt helt enkelt baserat på någon numerisk egenskap, så kan du bara returnera skillnaden mellan dem genom att subtrahera det ena från det andra. Precis som det gjordes i exemplet ovan."

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

"Jag tror att jag förstår allt. Men kanske inte. Men nästan allt."

"Bra. Låt oss nu överväga ett mer praktiskt problem. Anta att du har skrivit en cool webbplats för att tillverka damkläder i Kina. Du använder en kvinnoklass för att beskriva dina kunder. Du har till och med skapat en webbsida med en tabell där du kan se dem alla . Men det finns ett problem..."

"Ditt Woman-objekt innehåller inte bara en ålder, utan också en hel massa andra data: förnamn, efternamn, längd, vikt, antal barn, etc."

"Tabellen över användare har många kolumner, och här är frågan: hur sorterar du dina användare efter de olika kriterierna? Efter vikt, ålder, efternamn?"

"Hmm. Ja, jag ser ofta tabeller som låter dig sortera efter kolumn. Så, hur gör man det?"

"För detta har vi det andra gränssnittet jag ville berätta om idag: Comparator-gränssnittet. Det har också en jämförelsemetod, men det tar två argument, inte ett: int compare(T o1, T o2). Så här Arbetar:"

Exempel
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;
}
}
Ett exempel på hur det kan användas:
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);
}

"Jämförelsegränssnittet döljer inte logiken för objektjämförelse i klassen för de objekt som jämförs. Istället implementeras den i en separat klass."

"Så, jag skulle kunna skapa flera klasser som implementerar gränssnittet Comparator och låta var och en av dem jämföra olika egenskaper? Vikt i en, ålder i en annan och höjd i en tredje?"

"Ja, det är väldigt enkelt och bekvämt."

"Vi anropar bara metoden Collections.sort , och skickar en lista med objekt och ett annat specialobjekt som det andra argumentet, vilket implementerar gränssnittet Comparator och talar om för dig hur du korrekt jämför objektpar i sorteringsprocessen."

"Hmm. Jag tror att jag förstår allt. Låt mig prova. Låt oss säga att jag måste sortera användare efter vikt. Det skulle vara ungefär så här:"

Exempel på att sortera användare efter vikt:
Comparator<Woman> compareByWeight = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.weight - o2.weight;
}
};

Collections.sort(women, compareByWeight);

"Ja exakt."

"Jättebra. Men tänk om jag vill sortera i omvänd ordning?"

"Tänk på det. Svaret är väldigt enkelt!"

"Jag har det! Så här:"

Sortering i stigande ordning:
return o1.weight - o2.weight;
Sortering i fallande ordning:
return o2.weight – o1.weight;

"Rätt. Bra gjort."

"Och om jag vill sortera efter efternamn? Hur sorterar jag strängar, Bilaabo?"

"Klassen String implementerar redan compareTo-metoden. Du behöver bara kalla den:"

Exempel på att sortera användare efter namn:
Comparator<Woman> compareByName = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.name.compareTo(o2.name);
}
};

Collections.sort(women, compareByName);

"Det var en bra lektion, Bilaabo. Tack så mycket."

"Och tack till dig, min vän!"