Komparator, Sammlungen sortieren - 1

„Hallo, Amigo!“

„Hallo, Bilaabo!“

„Heute befassen wir uns mit einem kleinen, aber interessanten und nützlichen Thema: dem Sortieren von Sammlungen.“

„Sortieren? Davon habe ich etwas gehört.“

„Vor langer Zeit musste jeder Programmierer in der Lage sein, Sortieralgorithmen zu schreiben. Konnte und musste sie schreiben erfunden worden.

„In Java (und anderen Programmiersprachen) ist die Sortierung bereits implementiert.  Ihre Aufgabe besteht darin, zu lernen, wie man das, was bereits vorhanden ist, richtig nutzt.

"OK."

„Die Hilfsklasse „Collections“ verfügt über eine statische Sortiermethode, die zum Sortieren von Sammlungen – oder genauer gesagt von Listen – verwendet wird. Elemente in Maps und Sets haben keine Reihenfolge/Index, daher gibt es nichts zu sortieren.“

„Ja, ich erinnere mich. Ich habe diese Methode einmal verwendet, um eine Liste mit Zahlen zu sortieren.“

„Großartig. Aber diese Methode ist viel leistungsfähiger, als es auf den ersten Blick scheint. Sie kann nicht nur Zahlen, sondern auch beliebige Objekte nach beliebigen Kriterien sortieren. Zwei Schnittstellen helfen der Methode dabei: Comparable und Comparator .

„Manchmal müssen Sie Objekte sortieren, nicht Zahlen. Angenommen, Sie haben eine Liste mit Personen und möchten diese nach Alter sortieren. Dafür haben wir die Comparable-Schnittstelle.

„Lassen Sie mich zunächst ein Beispiel zeigen, dann wird alles klarer:“

Beispiel
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;
}
}
Ein Beispiel dafür, wie es verwendet werden könnte:
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);
}

„Um Objekte zu sortieren, müssen Sie zunächst wissen, wie man sie vergleicht. Dafür verwenden wir Comparable. Die Comparable- Schnittstelle ist generisch, das heißt, sie akzeptiert ein Typargument. Sie hat nur eine generische Methode: CompareTo(T o). Diese Methode vergleicht das aktuelle Objekt (this) und ein als Argument übergebenes Objekt (o). Mit anderen Worten, wir müssen diese Methode in unserer Klasse implementieren und sie dann verwenden, um das aktuelle Objekt (this) mit dem übergebenen Objekt zu vergleichen. "

„Und wie funktioniert „compareTo“? Ich habe erwartet, dass es „true“ oder „false“ zurückgibt, je nachdem, ob das übergebene Objekt größer oder kleiner ist.“

„Die Dinge sind hier schwieriger. Die Methode „compareTo“ gibt nicht „true/false“ zurück. Stattdessen gibt sie ein int zurück. Dies geschieht eigentlich der Einfachheit halber.

„Wenn ein Computer feststellen muss, ob eine Zahl größer als eine andere ist, subtrahiert er einfach die zweite Zahl von der ersten und schaut sich dann das Ergebnis an. Wenn das Ergebnis 0 ist, sind die Zahlen gleich. Wenn das Ergebnis kleiner als Null ist.“ , dann ist die zweite Zahl größer. Und wenn das Ergebnis größer als Null ist, dann ist die erste Zahl größer.“

„Hier gilt die gleiche Logik. Laut Spezifikation muss die Methode „compareTo“ Null zurückgeben, wenn die verglichenen Objekte gleich sind. Wenn die Methode „compareTo“ eine Zahl größer als Null zurückgibt, dann ist unser Objekt größer als das übergebene Objekt.“ „Wenn die Methode „compareTo Wenn die Methode eine Zahl kleiner als Null zurückgibt, ist „this“ kleiner als das übergebene Objekt.“

„Das ist ein bisschen seltsam.“

„Ja, aber wenn Sie Objekte einfach auf der Grundlage einer numerischen Eigenschaft vergleichen, können Sie die Differenz zwischen ihnen einfach durch Subtrahieren des einen vom anderen zurückgeben. Genauso, wie es im obigen Beispiel gemacht wurde.“

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

„Ich glaube, ich verstehe alles. Aber vielleicht auch nicht. Aber fast alles.“

„Großartig. Betrachten wir nun ein praktischeres Problem. Angenommen, Sie haben eine coole Website für die Herstellung von Damenbekleidung in China geschrieben. Sie verwenden eine „Woman“-Klasse, um Ihre Kunden zu beschreiben. Sie haben sogar eine Webseite mit einer Tabelle erstellt, in der Sie sie alle sehen können . Aber es gibt ein Problem…“

„Ihr Woman-Objekt enthält nicht nur ein Alter, sondern auch eine ganze Reihe weiterer Daten: Vorname, Nachname, Größe, Gewicht, Anzahl der Kinder usw.“

„Die Benutzertabelle hat viele Spalten, und hier stellt sich die Frage: Wie sortieren Sie Ihre Benutzer nach den verschiedenen Kriterien? Nach Gewicht, Alter, Nachname?“

„Hmm. Ja, ich sehe oft Tabellen, in denen man nach Spalten sortieren kann. Wie macht man das?“

„Dafür haben wir die zweite Schnittstelle, von der ich Ihnen heute erzählen wollte: die Comparator-Schnittstelle. Sie hat auch eine Vergleichsmethode, aber sie benötigt zwei Argumente, nicht eines: int Compare(T o1, T o2). So funktioniert es funktioniert:“

Beispiel
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;
}
}
Ein Beispiel dafür, wie es verwendet werden könnte:
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);
}

„Die Comparator-Schnittstelle verbirgt die Objektvergleichslogik nicht innerhalb der Klasse der zu vergleichenden Objekte. Stattdessen wird sie in einer separaten Klasse implementiert.“

„Ich könnte also mehrere Klassen erstellen, die die Comparator-Schnittstelle implementieren, und jede von ihnen unterschiedliche Eigenschaften vergleichen lassen? Gewicht in einer, Alter in einer anderen und Größe in einer dritten?“

„Ja, es ist sehr einfach und bequem.“

„Wir rufen einfach die Collections.sort- Methode auf und übergeben eine Liste von Objekten und ein weiteres spezielles Objekt als zweites Argument, das die Comparator- Schnittstelle implementiert und Ihnen sagt, wie Sie Objektpaare im Sortierprozess korrekt vergleichen.“

„Hmm. Ich glaube, ich verstehe alles. Lass es mich versuchen. Nehmen wir an, ich muss Benutzer nach Gewicht sortieren. Das würde ungefähr so ​​aussehen:“

Beispiel für die Sortierung von Benutzern nach Gewicht:
Comparator<Woman> compareByWeight = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.weight - o2.weight;
}
};

Collections.sort(women, compareByWeight);

"Ja genau."

„Großartig. Aber was ist, wenn ich in umgekehrter Reihenfolge sortieren möchte?“

„Denken Sie darüber nach. Die Antwort ist ganz einfach!“

„Ich habe es! So:“

Sortierung in aufsteigender Reihenfolge:
return o1.weight - o2.weight;
Sortierung in absteigender Reihenfolge:
return o2.weight – o1.weight;

„Richtig. Gut gemacht.“

„Und wenn ich nach Nachnamen sortieren möchte? Wie sortiere ich Zeichenfolgen, Bilaabo?“

„Die String-Klasse implementiert bereits die CompareTo-Methode. Sie müssen sie nur aufrufen:“

Beispiel für die Sortierung von Benutzern nach Namen:
Comparator<Woman> compareByName = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.name.compareTo(o2.name);
}
};

Collections.sort(women, compareByName);

„Das war eine tolle Lektion, Bilaabo. Vielen Dank.“

„Und ich danke dir, mein Freund!“