2009-12-22 12 views

Antwort

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 Person-Klasse implementieren. So etwas wie (aufsteigend): compare(Person a, Person b) = a.id < b.id ? -1 : (a.id == b.id) ? 0 : 1 oder Integer.valueOf(a.id).compareTo(Integer.valueOf(b.id)).

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

+0

Das ist ein etwas verwirrendes Beispiel, weil String Comparable implementiert. Und das - es gibt nicht das Geringste. – Bozho

+1

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

+1

Und ich denke, es ist ein ReverseComparator, anstatt Reserve ... –

0

Die Klasse java.util.Collection s verfügt über eine Sortiermethode, die eine Liste und eine benutzerdefinierte Comparator akzeptiert. Sie können Ihren eigenen Vergleicher definieren, um Ihr Person-Objekt nach Belieben zu sortieren.

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, es zu tun.

13

Ich würde einen Komparator für die Personenklasse erstellen, die mit einem bestimmten Sortierverhalten parametrisiert werden kann. Hier kann ich die Sortierreihenfolge einstellen, aber sie kann auch so geändert werden, dass auch andere Personenattribute sortiert werden können.

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); 
    } 
    } 
} 

(hoffe, es stellt sich jetzt, ich habe keine IDE oder JDK zur Hand, codiert 'blind')

bearbeiten

Dank Thomas, den Code bearbeitet. Ich würde nicht sagen, dass die Verwendung von Math.signum gut, performant, effektiv ist, aber ich möchte es als Erinnerung behalten, dass die compareTo-Methode jede Ganzzahl zurückgeben kann und das Multiplizieren mit (-1) fehlschlägt, wenn Implementierung gibt Integer.MIN_INTEGER zurück ... Und ich entfernte den Setter, weil es billig genug ist, um einen neuen PersonComparator zu erstellen, wenn es gerade benötigt wird.

Aber ich behalte das Boxen, weil es zeigt, dass ich auf eine vorhandene vergleichbare Implementierung angewiesen bin. Konnte etwas wie Comparable<Integer> age1 = new Integer(person1.getAge()); getan haben, aber das sah zu hässlich aus. Die Idee war, ein Muster zu zeigen, das leicht an andere Personenattribute angepasst werden kann, wie Name, Geburtstag als Datum und so weiter.

+4

Es war einmal eine gute Angewohnheit, einen Kommentar zu hinterlassen, um dem gerade herabgestimmten Autor zu helfen, seine Botschaft zu verbessern. –

+0

Ich habe nicht downvote, aber 'compare * (-1)' ist anfällig für Überlauf. Ich habe den gleichen Fehler in meinem ersten Post gemacht. –

+0

Und der SortOrder sollte im Konstruktor festgelegt werden und endgültig sein. Die Verwendung eines Wrappers ist ein besserer Ansatz, den ich vermute: 'new Reverse (new PersonComparator())' –

4

Mit Google Kollektionen:

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()); 
} 
+2

Overshooting mit Stil :) – Esko

58

Für was seinen Wert hier ist meine Standardantwort. Das einzige, was neu ist, ist, dass es die Collections.reverseOrder() verwendet. Außerdem ist es bringt alle Vorschläge in einem Beispiel:

/* 
** 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); 
    } 
} 
+0

das funktionierte wirklich für mich, und es ist auch eine sehr einfache Lösung (nur eine Zeile). –

+0

Perfektes Beispiel! Vielen Dank. –

+0

Gibt es eine Möglichkeit, Strings in einem TreeSet mit einem Vergleicher wie diesem zu sortieren? Gleiches, Leute nach Alter. – Zeff520

82

Sie die absteigende eines benutzerdefinierten tun können Klasse auf diese Weise das Überschreiben der compare() Methode,

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

Oder von Collection.reverse() mit sortieren absteigend als Benutzer Prince erwähnt in his comment.

Und Sie können wie folgt die aufsteigende tun,

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 mit einem Lambda-Ausdruck (Java 8 ab) wir prägnante erhalten:

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

Ab Java 8, Liste sort() Methode, die als Parameter nimmt Comparator (prägnante):

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

Hier werden a und b als Personentyp durch Lambda-Ausdruck abgeleitet.

+18

Oder Sie können einfach 'Collections.reverseOrder (...)' für die absteigende Sortierung verwenden. – Prince

+1

@Prince Kein Fan dieses Ansatzes, er zwingt mich, die ursprüngliche Methode zu betrachten, um zu sehen, wie die Dinge sortiert werden (nicht umgekehrt) –

+1

Erwähnenswert ist, dass 'compareToIgnoreCase' auch nützlich ist, wenn' String'-Objekte verglichen werden Meistens benutze ich das anstatt nur 'compareTo' –

Verwandte Themen