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:
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.
compareToIgnoreCaseauch beim Vergleichen von StringObjekten nützlich ist. Meistens verwende ich dies anstelle von nurcompareTo
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);
}
}
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.
compare * (-1)anfällig für Überlauf. Ich habe den gleichen Fehler in meinem ersten Beitrag gemacht.
new Reverse(new PersonComparator())
Integer age1 = ...;hat das Boxen über sich.
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()).
-1 * Integer.MIN_VALUE == Integer.MIN_VALUE. Welches ist nicht was du willst. Ich habe die Argumente ausgetauscht, die sowieso einfacher sind.
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.
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());
}
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.
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.
Collections.reverseOrder(...)für absteigende Sortierung verwenden.