Sortieren mit Komparator - Absteigende Reihenfolge (benutzerdefinierte Klassen) [geschlossen]


77

Ich möchte meine Objekte mit dem Komparator in absteigender Reihenfolge sortieren.

class Person {
 private int age;
}

Hier möchte ich ein Array von Personenobjekten sortieren.

Wie kann ich das machen?

Antworten:


117

Sie können die absteigende Sortierung einer benutzerdefinierten Klasse auf diese Weise ausführen, indem Sie die compare () -Methode überschreiben.

Collections.sort(unsortedList,new Comparator<Person>() {
    @Override
    public int compare(Person a, Person b) {
        return b.getName().compareTo(a.getName());
    }
});

Oder indem Sie Collection.reverse()absteigend als Benutzer sortieren, den Prince in seinem Kommentar erwähnt hat .

Und Sie können die aufsteigende Sortierung so machen,

Collections.sort(unsortedList,new Comparator<Person>() {
    @Override
    public int compare(Person a, Person b) {
        return a.getName().compareTo(b.getName());
    }
});

Ersetzen Sie den obigen Code durch einen Lambda-Ausdruck (ab Java 8).

Collections.sort(personList, (Person a, Person b) -> b.getName().compareTo(a.getName()));

Ab Java 8 verfügt List über die sort () -Methode, die Comparator als Parameter verwendet (prägnanter):

personList.sort((a,b)->b.getName().compareTo(a.getName()));

Hier aund bwerden als Personentyp durch Lambda-Ausdruck abgeleitet.


23
Oder Sie können nur Collections.reverseOrder(...)für absteigende Sortierung verwenden.
Prinz

1
@ Prince Kein Fan dieses Ansatzes, es zwingt mich, die ursprüngliche Methode zu betrachten, um zu sehen, wie die Dinge zunächst sortiert werden (nicht umgekehrt)
b1nary.atr0phy

1
Erwähnenswert ist, dass dies compareToIgnoreCaseauch beim Vergleichen von StringObjekten nützlich ist. Meistens verwende ich dies anstelle von nurcompareTo
Mark Keen

Lief wie am Schnürchen! Vielen Dank.
Herr Port St Joe

69

Für was es sich hier lohnt, ist meine Standardantwort. Neu ist nur, dass Collections.reverseOrder () verwendet wird. Außerdem werden alle Vorschläge in einem Beispiel zusammengefasst:

/*
**  Use the Collections API to sort a List for you.
**
**  When your class has a "natural" sort order you can implement
**  the Comparable interface.
**
**  You can use an alternate sort order when you implement
**  a Comparator for your class.
*/
import java.util.*;

public class Person implements Comparable<Person>
{
    String name;
    int age;

    public Person(String name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public String getName()
    {
        return name;
    }

    public int getAge()
    {
        return age;
    }

    public String toString()
    {
        return name + " : " + age;
    }

    /*
    **  Implement the natural order for this class
    */
    public int compareTo(Person p)
    {
        return getName().compareTo(p.getName());
    }

    static class AgeComparator implements Comparator<Person>
    {
        public int compare(Person p1, Person p2)
        {
            int age1 = p1.getAge();
            int age2 = p2.getAge();

            if (age1 == age2)
                return 0;
            else if (age1 > age2)
                return 1;
            else
                return -1;
        }
    }

    public static void main(String[] args)
    {
        List<Person> people = new ArrayList<Person>();
        people.add( new Person("Homer", 38) );
        people.add( new Person("Marge", 35) );
        people.add( new Person("Bart", 15) );
        people.add( new Person("Lisa", 13) );

        // Sort by natural order

        Collections.sort(people);
        System.out.println("Sort by Natural order");
        System.out.println("\t" + people);

        // Sort by reverse natural order

        Collections.sort(people, Collections.reverseOrder());
        System.out.println("Sort by reverse natural order");
        System.out.println("\t" + people);

        //  Use a Comparator to sort by age

        Collections.sort(people, new Person.AgeComparator());
        System.out.println("Sort using Age Comparator");
        System.out.println("\t" + people);

        //  Use a Comparator to sort by descending age

        Collections.sort(people,
            Collections.reverseOrder(new Person.AgeComparator()));
        System.out.println("Sort using Reverse Age Comparator");
        System.out.println("\t" + people);
    }
}

Das hat bei mir tatsächlich funktioniert und ist auch eine sehr einfache Lösung (nur eine Zeile).
Android-Entwickler

Perfektes Beispiel! Vielen Dank.
Michael Wildermuth

Gibt es eine Möglichkeit, Strings in einem TreeSet mit einem solchen Komparator zu sortieren? Das Gleiche, Menschen nach Alter.
Zeff520

Ich habe noch nie ein TreeSet verwendet, aber in der API-Dokumentation heißt es: - Die Elemente werden in ihrer natürlichen Reihenfolge oder von einem zum festgelegten Erstellungszeitpunkt bereitgestellten Komparator sortiert, je nachdem, welcher Konstruktor verwendet wird. Ich denke, dies ist möglich.
Camickr

17

Ich würde einen Komparator für die Personenklasse erstellen, der mit einem bestimmten Sortierverhalten parametrisiert werden kann. Hier kann ich die Sortierreihenfolge festlegen, sie kann jedoch geändert werden, um auch die Sortierung für andere Personenattribute zu ermöglichen.

public class PersonComparator implements Comparator<Person> {

  public enum SortOrder {ASCENDING, DESCENDING}

  private SortOrder sortOrder;

  public PersonComparator(SortOrder sortOrder) {
    this.sortOrder = sortOrder;
  }

  @Override
  public int compare(Person person1, Person person2) {
    Integer age1 = person1.getAge();
    Integer age2 = person2.getAge();
    int compare = Math.signum(age1.compareTo(age2));

    if (sortOrder == ASCENDING) {
      return compare;
    } else {
      return compare * (-1);
    }
  }
}

(Ich hoffe, es wird jetzt kompiliert. Ich habe keine IDE oder JDK zur Hand, codiert "blind".)

Bearbeiten

Dank Thomas hat der Code bearbeitet. Ich würde nicht sagen, dass die Verwendung von Math.signum gut, performant und effektiv ist, aber ich möchte daran erinnern, dass die compareTo-Methode eine beliebige Ganzzahl zurückgeben kann und das Multiplizieren mit (-1) fehlschlägt, wenn die Die Implementierung gibt Integer.MIN_INTEGER zurück ... Und ich habe den Setter entfernt, weil er billig genug ist, um einen neuen PersonComparator genau dann zu erstellen, wenn er benötigt wird.

Aber ich behalte das Boxen bei, weil es zeigt, dass ich mich auf eine vorhandene vergleichbare Implementierung verlasse. Hätte so etwas tun können, Comparable<Integer> age1 = new Integer(person1.getAge());aber das sah zu hässlich aus. Die Idee war, ein Muster zu zeigen, das leicht an andere Personenattribute wie Name, Geburtstag als Datum usw. angepasst werden kann.


6
Es war einmal eine gute Angewohnheit, einen Kommentar zu hinterlassen, um dem gerade herabgestuften Autor zu helfen, seine Botschaft zu verbessern.
Andreas Dolk

Ich habe nicht abgelehnt, bin aber compare * (-1)anfällig für Überlauf. Ich habe den gleichen Fehler in meinem ersten Beitrag gemacht.
Thomas Jung

Und der SortOrder sollte im Konstruktor festgelegt und endgültig sein. Die Verwendung eines Wrappers ist vermutlich ein besserer Ansatz:new Reverse(new PersonComparator())
Thomas Jung

Und Integer age1 = ...;hat das Boxen über sich.
Thomas Jung

Ja, ja, ja, genug Raum für Verbesserungen. Das Boxen war absichtlich und der Setter erlaubt es, den Komparator für aufsteigende und absteigende Reihenfolge zu verwenden. Andererseits haben Sie Recht, erstellen Sie besser jedes Mal eine neue, als sie wiederzuverwenden. Bauen ist billig genug.
Andreas Dolk

14
String[] s = {"a", "x", "y"};
Arrays.sort(s, new Comparator<String>() {

    @Override
    public int compare(String o1, String o2) {
        return o2.compareTo(o1);
    }
});
System.out.println(Arrays.toString(s));

-> [y, x, a]

Jetzt müssen Sie den Komparator für Ihre Personenklasse implementieren. So etwas wie (in aufsteigender Reihenfolge): compare(Person a, Person b) = a.id < b.id ? -1 : (a.id == b.id) ? 0 : 1oder Integer.valueOf(a.id).compareTo(Integer.valueOf(b.id)).

Um Verwirrung zu vermeiden, sollten Sie einen aufsteigenden Komparator implementieren und ihn mit einem Wrapper ( wie diesem ) in einen absteigenden konvertieren new ReverseComparator<Person>(new PersonComparator()).


Das ist ein etwas verwirrendes Beispiel, da String Comparable implementiert. Und das -1 gibt es nicht die direkteste Sache.
Bozho

1
Das beste Argument gegen -1 * x ist das -1 * Integer.MIN_VALUE == Integer.MIN_VALUE. Welches ist nicht was du willst. Ich habe die Argumente ausgetauscht, die sowieso einfacher sind.
Thomas Jung

1
Und ich denke, es ist ein ReverseComparator anstelle von Reserve ...
Adriaan Koster

Nun, das war nicht das beste Argument. Für Anfänger war es nur verwirrend :) Es ist immer noch so, weil er wissen müsste, was Vergleichbar ist, und erkennen muss, dass seine Person es nicht implementiert. Aber dann - Denken ist eine gute Sache :)
Bozho

Integer.compareerwähnt in der Dokumentation Folgendes : The value returned is identical to what would be returned by: Integer.valueOf(x).compareTo(Integer.valueOf(y)), damit Sie Integer.comparestattdessen verwenden können.
Keyser

5

Verwenden von Google-Sammlungen:

class Person {
 private int age;

 public static Function<Person, Integer> GET_AGE =
  new Function<Person, Integer> {
   public Integer apply(Person p) { return p.age; }
  };

}

public static void main(String[] args) {
 ArrayList<Person> people;
 // Populate the list...

 Collections.sort(people, Ordering.natural().onResultOf(Person.GET_AGE).reverse());
}

0
package com.test;

import java.util.Arrays;

public class Person implements Comparable {

private int age;

private Person(int age) {
    super();
    this.age = age;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

@Override
public int compareTo(Object o) {
    Person other = (Person)o;
    if (this == other)
        return 0;
    if (this.age < other.age) return 1;
    else if (this.age == other.age) return 0;
    else return -1;

}

public static void main(String[] args) {

    Person[] arr = new Person[4];
    arr[0] = new Person(50);
    arr[1] = new Person(20);
    arr[2] = new Person(10);
    arr[3] = new Person(90);

    Arrays.sort(arr);

    for (int i=0; i < arr.length; i++ ) {
        System.out.println(arr[i].age);
    }
}

}

Hier ist eine Möglichkeit, dies zu tun.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.