Comparable Interface für Objektvergleiche nutzen

Kornblume

Mitglied
Hallo zusammen,

ich bin neu in Sachen Java, also bitte verzeiht mir, falls ich in der Beschreibung meines Problems Fehler mache 🙂
Ich würde gerne eine ArrayList mit Objekten, die jeweils zwei Attribute haben, über einen Algorithmus sortieren lassen. Da in den Attributen auch Buchstaben vorkommen, sie also gewissermaßen einen String darstellen, habe ich etwas im Internet geschaut und bin auf das Comparable Interface mit der Methode "compareTo()" gestoßen.
Jetzt ist mir noch nicht ganz klar, wie ich das dann in der Praxis benutzen kann.
Füge ich das "...implements Comparable" in der Klasse meines Objekts ein, oder in der Klasse, in der ich meine Methode schreibe ?
Wie benutze ich "compareTo" am Besten, wenn ich das Attribut spezifizieren möchte, nachdem es die Objekte ordnet ?

Ich hoffe ihr konntet mich einigermaßen verstehen!

Vielen Dank für alle Antworten 🙂
 
Es gibt sehr viele Möglichkeiten eine Sortierung zu erreichen. Ich persönlich implementiere nicht mehr Comparable<T> auf meine Datenklasse, da man sich mit dem Interface auf eine bestimmte Sortierung festlegt.
Ich mache es lieber so, dass ich einen Methode habe, die mir einen Comparator zurückgibt. Das kann eine innere Klasse sein oder in einer extra Datei liegen oder nur als Lambda-Ausdruck.
Hier am Beispiel mit Koordinaten, welches du durch Anpassen der compare und den Typen für dein String-Problem umschreiben kannst.
Java:
    /**
     * Comparator to compare by distance.
     */
    class DistanceToOrder implements Comparator<Coordinate2D> {
        @Override
        public int compare(Coordinate2D e1, Coordinate2D e2) {
            int dist1 = distanceSquaredTo(e1);
            int dist2 = distanceSquaredTo(e2);
            return Integer.compare(dist1, dist2);
        }
    }
    /**
     * Compares two points by distance.
     *
     * @return the comparator
     */
    public Comparator<Coordinate2D> distanceToOrderLambda() {
        return (o1, o2) -> {
            int dist1 = distanceSquaredTo(o1);
            int dist2 = distanceSquaredTo(o2);
            return Integer.compare(dist1, dist2);
        };
    }
    /**
     * Compares two points by distance.
     *
     * @return the comparator
     */
    public Comparator<Coordinate2D> distanceToOrder() {
        return new DistanceToOrder();
    }
Und sortieren kannst du dann mit Collectios.sort
Java:
static <T> void sort(List<T> list, Comparator<? super T> c)
Und sonst gibt es ettliche Tutorials dazu. Eins davon zeigt beide Ansätze mit Comparable und Comparator.
 
Ich persönlich implementiere nicht mehr Comparable<T> auf meine Datenklasse, da man sich mit dem Interface auf eine bestimmte Sortierung festlegt.
Comparable ist ein Interface für die natürliche Ordnung. D.h. da gibt es keinen Interpretationsspielraum, wie zum Beispiel bei den natürlichen Zahlen. Das ist fix vordefiniert.

Man kann beides Implementieren, wenn es eine natürliche Ordnung gibt Comparable und wenn man eine spezielle Sortierung haben möchte, dann Comparator.
 
Ich meinte, dass man sich auf eine Ordnung anhand bestimmter Attribute festlegt aber oft je nach Ansicht nach verschiedenen Aspekten sortieren möchte. So kann man Personen nach Alter oder Namen sortieren - mach das mal mit der Implementierung von Comparable.
 
Ich meinte, dass man sich auf eine Ordnung anhand bestimmter Attribute festlegt aber oft je nach Ansicht nach verschiedenen Aspekten sortieren möchte. So kann man Personen nach Alter oder Namen sortieren - mach das mal mit der Implementierung von Comparable.
Das ist auch eben nicht der Sinn von Compareable - Personen haben keine natürliche Ordung, also implementiert man sie auch nicht 😉
 
Ich meinte, dass man sich auf eine Ordnung anhand bestimmter Attribute festlegt aber oft je nach Ansicht nach verschiedenen Aspekten sortieren möchte. So kann man Personen nach Alter oder Namen sortieren - mach das mal mit der Implementierung von Comparable.


etwas ähnliches bräuchte ich.
Ist es möglich zwei Versionen von compareTo zu implementieren, die den Sortierfokus jeweils auf ein anderes Attribut legen ?
 
Ist es möglich zwei Versionen von compareTo zu implementieren, die den Sortierfokus jeweils auf ein anderes Attribut legen ?
Genau das ist der Fokus meines Ansatzes ein Comparator zu liefern. Du kannst pro Sortierung/Ansicht einen separaten Comparator anlegen.
Wann man Comparable und wann Comparator einsetzt war mir nur anhand dieses Vorteils bekannt. Dass es auf die natürliche Ordnung zurückzuführen ist war mich dabei nicht bewusst.
 
Dafür nutzt man Comparator 😉

Achso, auch wenn man nur das Attribut ändern möchte ? Bsp. bei der Modellierung eines Menschen auf "Alter", "Größe", "Name", etc. ?
Ich habe das bei euch bislang so verstanden, dass man Comparator benutzt, wenn man die Sortierreihenfolge ändern möchte, also so etwas wie die Sortierregeln.
Da Buchstaben und Zahlen ja eine solche haben (bei Buchstaben dann anhand des ASCII Codes, oder?), bräuchte ich das ja nicht
 
Das ist doch das passende Stichwort: andere Attribute nach denen Sortiert wird = andere Sortierregeln 😉

Ok, dann glaube ich, dass ich das jetzt verstanden habe ;-)
Danke!

Wie sieht es dann mit der Anwendung von compareTo aus ?
Funktioniert das dann nur mittels Collections.sort oder kann ich die neue Regel auch innerhalb von einem selbst implementierten Sortieralgorithmus verwenden? Ich meine hierbei dann so etwas wie Quicksort, Heapsort, Mergesort.

Denn das wäre ja meine Anforderung in diesem Fall
 
Wie sieht es dann mit der Anwendung von compareTo aus ?
Funktioniert das dann nur mittels Collections.sort oder kann ich die neue Regel auch innerhalb von einem selbst implementierten Sortieralgorithmus verwenden? Ich meine hierbei dann so etwas wie Quicksort, Heapsort, Mergesort.

Denn das wäre ja meine Anforderung in diesem Fall
Natürlich kannst du die auch in deinem eigenen Algorithmus verwenden, es ist ja nur eine Methode, die was zurück gibt. Wer die aufruft, ist egal
 
compareTo ist überall dort sinnvoll, wo vordefiniert ist, was rauskommen soll, wenn sich ein Objekt mit einem zweiten vergleichen soll. Die Methode selbst sortiert nicht. Sie liefert lediglich die Information, ob die andere Variable weiter hinten oder weiter vorne in der Liste stehen soll, der verwendete Sortieralgorithmus macht den Rest.

Wenn du verschiedene Sortierkriterien willst, ist ein Comparator tatsächlich die richtige Herangehensweise.
Z.B. kannst du im Konstruktor übergeben, nach welchen Kriterien sortiert werden soll. In der compare-Methode folgst du dann den Anweisungen.
Hier ein einfaches Beispiel
Java:
    /**
     * Komparator f&uuml;r Punkte
     */
    public class SortPointsXY implements Comparator<Point2D.Double> {

        private final boolean xFirst;

        /**
         * Comparator für Punkte
         *
         * @param xFirst: true: Zuerst nach X sortieren.
         * <br>false: Zuerst nach Y sortieren
         */
        public SortPointsXY(boolean xFirst) {
            this.xFirst = xFirst;
        }

        @Override
        public int compare(Point2D.Double p1, Point2D.Double p2) {
            int result;
            if (xFirst) {
                result = Double.compare(p1.getX(), p2.getX());
                if (result == 0) {
                    result = Double.compare(p1.getY(), p2.getY());
                }
            } else {
                result = Double.compare(p1.getY(), p2.getY());
                if (result == 0) {
                    //Hier mal ein Beispiel mit compareTo. p1.getX() vergleicht sich mit p2.getX()
                    //Der erste Cast ist notwendig,
                    //weil "double" eine primitiver Datentyp ist und die Methode somit gar nicht hat.
                    //an der zweiten Stelle muss man dank Javas Autoboxing nicht casten.
                    result = ((Double) p1.getX()).compareTo(p2.getX());
                }
            }
            return result;
        }
    }

Es gibt gewisse Vorgaben für die Compare-Methode (bzw. compareTo), aber über die stolperst du noch früh genug.
Wenn du mit funktionaler Programmierung arbeitest, muss die Compare-Methode die Informationen, wie sie sortieren soll, natürlich von einer andereren Stelle kriegen. Nur selten ist die compareTo-Methode geeignet, wenn es mehr als eine Eigenschaft zum Vergleichen gibt.
 
Wenn du verschiedene Sortierkriterien willst, ist ein Comparator tatsächlich die richtige Herangehensweise.
Z.B. kannst du im Konstruktor übergeben, nach welchen Kriterien sortiert werden soll. In der compare-Methode folgst du dann den Anweisungen.
In dem Fall eigenen ich eher getrennte Comparatoren für die unterschiedlichen Kriterien (oder einfach Comparator-Chaining)

Wenn du mit funktionaler Programmierung arbeitest, muss die Compare-Methode die Informationen, wie sie sortieren soll, natürlich von einer andereren Stelle kriegen.
Was ändert daran funktionale Programmierung? 😵
 
In dem Fall eigenen ich eher getrennte Comparatoren für die unterschiedlichen Kriterien (oder einfach Comparator-Chaining)
Auch ok, das war ja nur ein Beispiel.
Was ändert daran funktionale Programmierung? 😵
Ich hab den Parameter über den Konstruktor reingeschickt. Mit Lambda oder einem Funktionsverweis geht das nicht, bzw. mir wäre nichts dergleichen bekannt.
Chaining könnte wohl effizienter sein, auf jeden Fall ist damit das Risiko von Tippfehlern geringer 🙂
Es handelt sich hier wirklich nur um ein Beispiel, nicht die ultimative Lösung aller Probleme.
 

Zurück
Oben