Ich habe über das Sortieren von ArrayLists mit einem Comparator gelesen, aber in allen Beispielen benutzten die Leute compareTo
, was nach einigen Recherchen eine Methode für Strings ist.
Ich wollte eine ArrayList von benutzerdefinierten Objekten nach einer ihrer Eigenschaften sortieren: einem Date-Objekt (getStartDay()
). Normalerweise vergleiche ich sie mit item1.getStartDate().before(item2.getStartDate())
, also habe ich mich gefragt, ob ich so etwas schreiben könnte:
public class CustomComparator {
public boolean compare(Object object1, Object object2) {
return object1.getStartDate().before(object2.getStartDate());
}
}
public class RandomName {
...
Collections.sort(Database.arrayList, new CustomComparator);
...
}
Da Date
implementiert Comparable
hat, hat es eine compareTo
-Methode, genau wie String
.
So könnte Ihre benutzerdefinierte Comparator
so aussehen:
public class CustomComparator implements Comparator<MyObject> {
@Override
public int compare(MyObject o1, MyObject o2) {
return o1.getStartDate().compareTo(o2.getStartDate());
}
}
Die compare()
-Methode muss eine int
zurückgeben, sodass Sie eine boolean
nicht so wie Sie es ohnehin geplant hatten, direkt zurückgeben können.
Ihr Sortiercode wäre ungefähr so, wie Sie geschrieben haben:
Collections.sort(Database.arrayList, new CustomComparator());
Ein etwas kürzerer Weg, all dies zu schreiben, wenn Sie Ihren Vergleicher nicht wiederverwenden müssen, ist es als anonyme Inline-Klasse zu schreiben:
Collections.sort(Database.arrayList, new Comparator<MyObject>() {
@Override
public int compare(MyObject o1, MyObject o2) {
return o1.getStartDate().compareTo(o2.getStartDate());
}
});
Sie können jetzt das letzte Beispiel in kürzerer Form schreiben, indem Sie einen Lambda-Ausdruck für die Comparator
verwenden:
Collections.sort(Database.arrayList,
(o1, o2) -> o1.getStartDate().compareTo(o2.getStartDate()));
Und List
verfügt über eine sort(Comparator)
-Methode, sodass Sie diese noch weiter verkürzen können:
Database.arrayList.sort((o1, o2) -> o1.getStartDate().compareTo(o2.getStartDate()));
Dies ist eine solche verbreitete Redewendung, dass eine integrierte Methode zum Generieren einer Comparator
für eine Klasse mit einem Comparable
-Schlüssel vorhanden ist:
Database.arrayList.sort(Comparator.comparing(MyObject::getStartDate));
All dies sind gleichwertige Formen.
Klassen, die eine natürliche Sortierreihenfolge haben (eine Klassennummer als Beispiel), sollten die Comparable-Schnittstelle implementieren, während Klassen, die keine natürliche Sortierreihenfolge haben (beispielsweise ein Klassenlehrstuhl), mit einem Comparator (oder einem anonymen Comparator) versehen werden sollten Klasse).
Zwei Beispiele:
public class Number implements Comparable<Number> {
private int value;
public Number(int value) { this.value = value; }
public int compareTo(Number anotherInstance) {
return this.value - anotherInstance.value;
}
}
public class Chair {
private int weight;
private int height;
public Chair(int weight, int height) {
this.weight = weight;
this.height = height;
}
/* Omitting getters and setters */
}
class ChairWeightComparator implements Comparator<Chair> {
public int compare(Chair chair1, Chair chair2) {
return chair1.getWeight() - chair2.getWeight();
}
}
class ChairHeightComparator implements Comparator<Chair> {
public int compare(Chair chair1, Chair chair2) {
return chair1.getHeight() - chair2.getHeight();
}
}
Verwendungszweck:
List<Number> numbers = new ArrayList<Number>();
...
Collections.sort(numbers);
List<Chair> chairs = new ArrayList<Chair>();
// Sort by weight:
Collections.sort(chairs, new ChairWeightComparator());
// Sort by height:
Collections.sort(chairs, new ChairHeightComparator());
// You can also create anonymous comparators;
// Sort by color:
Collections.sort(chairs, new Comparator<Chair>() {
public int compare(Chair chair1, Chair chair2) {
...
}
});
Um eine ArrayList
zu sortieren, können Sie den folgenden Code-Ausschnitt verwenden:
Collections.sort(studList, new Comparator<Student>(){
public int compare(Student s1, Student s2) {
return s1.getFirstName().compareToIgnoreCase(s2.getFirstName());
}
});
Ja, du kannst. Es gibt zwei Optionen zum Vergleichen von Elementen, die Comparable - Schnittstelle und die Comparator - Schnittstelle.
Beide Schnittstellen ermöglichen unterschiedliches Verhalten. Mit Comparable können Sie das Objekt so verhalten, wie Sie es gerade beschrieben haben: Strings (tatsächlich implementiert String Comparable). Der zweite Komparator ermöglicht Ihnen, das zu tun, was Sie möchten. Sie würden es so machen:
Collections.sort(myArrayList, new MyComparator());
Dies führt dazu, dass die Collections.sort-Methode Ihren Vergleicher für den Sortiermechanismus verwendet. Wenn die Objekte in der ArrayList vergleichbar implementiert werden, können Sie stattdessen Folgendes tun:
Collections.sort(myArrayList);
Die Klasse Collections enthält eine Reihe dieser nützlichen, üblichen Werkzeuge.
Collections.sort(studList, (Student s1, Student s2) ->{
return s1.getFirstName().compareToIgnoreCase(s2.getFirstName());
});
Comparator<Student> c = (s1, s2) -> s1.firstName.compareTo(s2.firstName);
studList.sort(c)
Mit Java 8 können Sie eine Methodenreferenz für Ihren Vergleicher verwenden:
import static Java.util.Comparator.comparing;
Collections.sort(list, comparing(MyObject::getStartDate));
import Java.text.ParseException;
import Java.text.SimpleDateFormat;
import Java.util.ArrayList;
import Java.util.Collections;
import Java.util.Comparator;
import Java.util.Date;
public class test {
public static class Person {
public String name;
public int id;
public Date hireDate;
public Person(String iname, int iid, Date ihireDate) {
name = iname;
id = iid;
hireDate = ihireDate;
}
public String toString() {
return name + " " + id + " " + hireDate.toString();
}
// Comparator
public static class CompId implements Comparator<Person> {
@Override
public int compare(Person arg0, Person arg1) {
return arg0.id - arg1.id;
}
}
public static class CompDate implements Comparator<Person> {
private int mod = 1;
public CompDate(boolean desc) {
if (desc) mod =-1;
}
@Override
public int compare(Person arg0, Person arg1) {
return mod*arg0.hireDate.compareTo(arg1.hireDate);
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SimpleDateFormat df = new SimpleDateFormat("mm-dd-yyyy");
ArrayList<Person> people;
people = new ArrayList<Person>();
try {
people.add(new Person("Joe", 92422, df.parse("12-12-2010")));
people.add(new Person("Joef", 24122, df.parse("1-12-2010")));
people.add(new Person("Joee", 24922, df.parse("12-2-2010")));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Collections.sort(people, new Person.CompId());
System.out.println("BY ID");
for (Person p : people) {
System.out.println(p.toString());
}
Collections.sort(people, new Person.CompDate(false));
System.out.println("BY Date asc");
for (Person p : people) {
System.out.println(p.toString());
}
Collections.sort(people, new Person.CompDate(true));
System.out.println("BY Date desc");
for (Person p : people) {
System.out.println(p.toString());
}
}
}
Da Technologien täglich erscheinen, wird sich die Antwort mit der Zeit ändern. Ich habe mir LambdaJ angesehen und erscheint sehr interessant.
Sie können versuchen, diese Aufgaben mit LambdaJ zu lösen. Sie finden es hier: http://code.google.com/p/lambdaj/
Hier haben Sie ein Beispiel:
Iterativ sortieren
List<Person> sortedByAgePersons = new ArrayList<Person>(persons);
Collections.sort(sortedByAgePersons, new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
}
});
Sortiere mit Lambda
List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge());
Natürlich hat diese Art von Schönheit Auswirkungen auf die Leistung (im Durchschnitt 2 Mal), aber können Sie einen besser lesbaren Code finden?
Der einfachste Weg mit Java 8 ist für englische alphabetische Sortierung
Klassenimplementierung
public class NewspaperClass implements Comparable<NewspaperClass>{
public String name;
@Override
public int compareTo(NewspaperClass another) {
return name.compareTo(another.name);
}
}
Sortieren
Collections.sort(Your List);
Wenn Sie nach Alphabet sortieren möchten, das nicht englische Zeichen enthält, können Sie Gebietsschema verwenden.
Klassenimplementierung
public class NewspaperClass implements Comparator<NewspaperClass> {
public String name;
public Boolean isUserNewspaper=false;
private Collator trCollator = Collator.getInstance(new Locale("tr_TR"));
@Override
public int compare(NewspaperClass lhs, NewspaperClass rhs) {
trCollator.setStrength(Collator.PRIMARY);
return trCollator.compare(lhs.name,rhs.name);
}
}
Sortieren
Collections.sort(your array list,new NewspaperClass());
Ab Java 8
und weiter müssen wir Collections.sort()
nicht direkt verwenden. Die Variable List
hat eine Standardmethode sort()
:
List<User> users = Arrays.asList(user1,user2,user3);
users.sort( (u1, u2) -> {
return u1.getFirstName.compareTo(u2.getFirstName());});
Siehe http://visvv.blogspot.in/2016/01/sorting-objects-in-Java-8.html .
Die Collections.sort
- Methode kann eine List
sortieren, indem Sie eine Comparator
verwenden, die Sie übergeben. Diese Comparator
kann mit der Comparator.comparing
-Methode implementiert werden, bei der Sie eine Methodenreferenz als erforderliche Function
übergeben können. Glücklicherweise ist der eigentliche Code viel einfacher und kürzer als diese Beschreibung.
Für Java 8:
Collections.sort(list, comparing(ClassName::getName));
oder
Collections.sort(list, comparing(ClassName::getName).reversed());
Ein anderer Weg ist
Collections.sort(list, comparing(ClassName::getName, Comparator.nullsLast(Comparator.naturalOrder())));
Java 8 Lambda verkürzt die Sortierung.
Collections.sort(stdList, (o1, o2) -> o1.getName().compareTo(o2.getName()));
Sie können Guava ausprobieren Bestellung :
Function<Item, Date> getStartDate = new Function<Item, Date>() {
public Date apply(Item item) {
return item.getStartDate();
}
};
List<Item> orderedItems = Ordering.natural().onResultOf(getStartDate).
sortedCopy(items);
Sie können mit Java 8 sortieren
yourList.sort(Comparator.comparing(Classname::getName));
or
yourList.stream().forEach(a -> a.getBObjects().sort(Comparator.comparing(Classname::getValue)));
Sie können den Bean Comparator verwenden, um nach einer beliebigen Eigenschaft in Ihrer benutzerdefinierten Klasse zu sortieren.
Ja, das ist zum Beispiel in dieser Antwort ich sortiere nach der Eigenschaft v
der Klasse IndexValue
// Sorting by property v using a custom comparator.
Arrays.sort( array, new Comparator<IndexValue>(){
public int compare( IndexValue a, IndexValue b ){
return a.v - b.v;
}
});
Wenn Sie hier feststellen, erstelle ich eine anonyme innere Klasse (die Java für Schließungen ist) und leite sie direkt an die sort
-Methode der Klasse Arrays
weiter.
Ihr Objekt kann auch Comparable
implementieren (das ist es, was String und die meisten der Kernbibliotheken in Java tun), aber dies würde die "natürliche Sortierreihenfolge" der Klasse selbst definieren und Sie können keine neuen hinzufügen.
Ich fand, dass die meisten, wenn nicht alle dieser Antworten auf der zugrunde liegenden Klasse (Object) basieren, um vergleichbare oder eine vergleichbare Schnittstelle für Helfer zu implementieren.
Nicht bei meiner Lösung! Mit dem folgenden Code können Sie das Feld des Objekts vergleichen, indem Sie den Namen der Zeichenfolge kennen. Sie können es leicht ändern, um den Namen nicht zu verwenden, aber dann müssen Sie ihn freigeben oder eines der Objekte erstellen, mit denen Sie vergleichen möchten.
Collections.sort(anArrayListOfSomeObjectPerhapsUsersOrSomething, new ReflectiveComparator(). new ListComparator("name"));
public class ReflectiveComparator {
public class FieldComparator implements Comparator<Object> {
private String fieldName;
public FieldComparator(String fieldName){
this.fieldName = fieldName;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public int compare(Object object1, Object object2) {
try {
Field field = object1.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
Comparable object1FieldValue = (Comparable) field.get(object1);
Comparable object2FieldValue = (Comparable) field.get(object2);
return object1FieldValue.compareTo(object2FieldValue);
}catch (Exception e){}
return 0;
}
}
public class ListComparator implements Comparator<Object> {
private String fieldName;
public ListComparator(String fieldName) {
this.fieldName = fieldName;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public int compare(Object object1, Object object2) {
try {
Field field = object1.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
Comparable o1FieldValue = (Comparable) field.get(object1);
Comparable o2FieldValue = (Comparable) field.get(object2);
if (o1FieldValue == null){ return -1;}
if (o2FieldValue == null){ return 1;}
return o1FieldValue.compareTo(o2FieldValue);
} catch (NoSuchFieldException e) {
throw new IllegalStateException("Field doesn't exist", e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Field inaccessible", e);
}
}
}
}
Diese Codeausschnitte können hilfreich sein. Wenn Sie ein Objectin meinem Fall sortieren möchten, möchte ich nach VolumeName sortieren:
public List<Volume> getSortedVolumes() throws SystemException {
List<Volume> volumes = VolumeLocalServiceUtil.getAllVolumes();
Collections.sort(volumes, new Comparator<Volume>() {
public int compare(Volume o1, Volume o2) {
Volume p1 = (Volume) o1;
Volume p2 = (Volume) o2;
return p1.getVolumeName().compareToIgnoreCase(
p2.getVolumeName());
}
});
return volumes;
}
Das funktioniert. Ich benutze es in meinem jsp.
Sie können sich diese Präsentation 2016 auf dem Java Forum in Stuttgart Deutschland ansehen.
Nur wenige Folien verwenden die deutsche Sprache, 99% des Inhalts ist Java-Quellcode "Englisch". mögen
someCollection.sort(
OurCustomComparator
.comparing(Person::getName)
.thenComparing(Person::getId)
);
dabei verwendet OurCustomComparator
Standardmethoden (und andere interessante Ideen). Wie gezeigt, führt dies zu einem sehr prägnanten Code, um eine Getter-Methode zum Sortieren auszuwählen; und super einfache Verkettung (oder Umkehrung) von Sortierkriterien.
Wenn Sie sich für Java8 interessieren, finden Sie dort viel Material, um Ihnen den Einstieg zu erleichtern.
ihre customComparator-Klasse muss Java.util.Comparator implementieren, damit sie verwendet werden kann . Außerdem muss compare () AND equals () übergangen werden.
compare () muss die Frage beantworten: Ist Objekt 1 kleiner als, gleich oder größer als Objekt 2?
vollständige Dokumente: http://Java.Sun.com/j2se/1.5.0/docs/api/Java/util/Comparator.html
Mit dieser Bibliothek hier können Sie die Liste der benutzerdefinierten Objekte in mehreren Spalten sortieren. Die Bibliothek verwendet Funktionen der Version 8.0. Muster gibt es auch dort. Hier ist ein Beispiel zu tun
SortKeys sortKeys = new SortKeys();
sortKeys.addField("firstName")
.addField("age", true); // This (true) will sort the age descending
// Other ways to specify a property to the sorter are
// .addField("lastName", String.class);
// .addField("dob", Date.class, true);
// Instantiate a ListSorter
ListSorter listSorter = new ListSorter();
// Pass the data to sort (listToSort) and the "by keys" to sort (sortKeys)
List sortedList = (List<Person>) listSorter.sortList(listToSort, sortKeys);
Neu seit 1.8 ist eine List.sort () - Methode, anstatt die Collection.sort () Zu verwenden.
Hier ist ein Codeausschnitt, der die List.sort () - Funktion veranschaulicht:
List<Fruit> fruits = new ArrayList<Fruit>();
fruits.add(new Fruit("Kiwi","green",40));
fruits.add(new Fruit("Banana","yellow",100));
fruits.add(new Fruit("Apple","mixed green,red",120));
fruits.add(new Fruit("Cherry","red",10));
// a) using an existing compareto() method
fruits.sort((Fruit f1,Fruit f2) -> f1.getFruitName().compareTo(f2.getFruitName()));
System.out.println("Using String.compareTo(): " + fruits);
//Using String.compareTo(): [Apple is: mixed green,red, Banana is: yellow, Cherry is: red, Kiwi is: green]
// b) Using a comparable class
fruits.sort((Fruit f1,Fruit f2) -> f1.compareTo(f2));
System.out.println("Using a Comparable Fruit class (sort by color): " + fruits);
// Using a Comparable Fruit class (sort by color): [Kiwi is green, Apple is: mixed green,red, Cherry is: red, Banana is: yellow]
Die Fruchtklasse ist:
public class Fruit implements Comparable<Fruit>
{
private String name;
private String color;
private int quantity;
public Fruit(String name,String color,int quantity)
{ this.name = name; this.color = color; this.quantity = quantity; }
public String getFruitName() { return name; }
public String getColor() { return color; }
public int getQuantity() { return quantity; }
@Override public final int compareTo(Fruit f) // sorting the color
{
return this.color.compareTo(f.color);
}
@Override public String toString()
{
return (name + " is: " + color);
}
} // end of Fruit class
Ich bevorzuge diesen Prozess:
public class SortUtil
{
public static <T> List<T> sort(List<T> list, String sortByProperty)
{
Collections.sort(list, new BeanComparator(sortByProperty));
return list;
}
}
List<T> sortedList = SortUtil<T>.sort(unsortedList, "startDate");
Wenn die Liste der Objekte eine Eigenschaft namens startDate
enthält, rufen Sie diese immer wieder auf. Sie können sie sogar startDate.time
ketten.
Dies erfordert, dass Ihr Objekt Comparable
ist. Dies bedeutet, dass Sie eine compareTo
-, equals
- und hashCode
-Implementierung benötigen.
Ja, es könnte schneller sein ... Aber jetzt müssen Sie keinen neuen Komparator für jeden Sortentyp erstellen. Wenn Sie Dev-Zeit sparen und auf Laufzeit verzichten können, sollten Sie sich für diese entscheiden.
Bei Verwendung von Java 8 kann Comparator
in einer Zeile mit Comparator.comparing()
definiert werden.
Verwenden Sie eine der folgenden Methoden:
Option 1:
listToBeSorted.sort(Comparator.comparing(CustomObject::getStartDate));
Option 2:
Collections.sort(listToBeSorted, Comparator.comparing(CustomObject::getStartDate));
Ihre benutzerdefinierte Klasse kann die Schnittstelle "Comparable" implementieren, für die die CompareTo-Methode implementiert werden muss. In der CompareTo-Methode können Sie dann definieren, was bedeutet, dass ein Objekt kleiner oder größer als das andere Objekt ist. In Ihrem Beispiel kann es ungefähr so aussehen:
public class MyCustomClass implements Comparable<MyCustomClass>{
..........
@Override
public int compareTo(MyCustomClass a) {
if(this.getStartDate().before(a.getStartDate())){
return -1;
}else if(a.getStartDate().before(this.getStartDate())){
return 1;
}else {
return 0;
}
}
Eine negative Zahl bedeutet, dass this kleiner ist als das Objekt, mit dem verglichen wird. Eine positive Zahl zeigt an, dass this größer ist als das verglichen mit dem Objekt, und eine Null bedeutet, dass die Objekte gleich sind.
Sie können dann mit Collections.sort (myList) Ihre Liste sortieren, ohne einen Vergleicher eingeben zu müssen. Diese Methode hat auch den Vorteil, dass die Dinge automatisch sortiert werden, wenn Sie sortierte Auflistungsdatenstrukturen wie TreeSet oder TreeMap verwenden.
Sie können diesen Artikel lesen, wenn Sie mehr über die Comparable-Benutzeroberfläche erfahren möchten (Offenlegung: Ich bin der Autor;)) von-Sammlungen/