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?

Manoj
quelle

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.

Glücklich
quelle
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);
    }
}
camickr
quelle
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.

Andreas Dolk
quelle
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()).

Thomas Jung
quelle
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());
}
finnw
quelle
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.

Shamik
quelle
0

Die Klasse java.util.Collection verfügt über eine Sortiermethode, die eine Liste und einen benutzerdefinierten Komparator verwendet . Sie können Ihren eigenen Komparator definieren, um Ihr Personenobjekt nach Belieben zu sortieren.

Robert Christie
quelle