Objekte in ArrayList nach Datum sortieren?


149

In jedem Beispiel, das ich finde, geht es darum, dies alphabetisch zu tun, während ich meine Elemente nach Datum sortieren muss.

Meine ArrayList enthält Objekte, für die eines der Datenmitglieder ein DateTime-Objekt ist. Auf DateTime kann ich folgende Funktionen aufrufen:

lt() // less-than
lteq() // less-than-or-equal-to

Zum Vergleich könnte ich so etwas tun wie:

if(myList.get(i).lt(myList.get(j))){
    // ...
}

Was soll ich im if-Block tun?


3
Ich habe die Lösung veröffentlicht, aber wenn Sie einen Einblick in die Bestellung erhalten möchten, sollten Sie sich über Bestellalgorithmen (Bubblesort, Mergesort, Quicksort usw.) informieren.
Helios

Danke, ich werde mir diese ansehen, ich weiß nichts über Sortieren

In diesem Thread finden Sie einige nützliche Java 1.8-Lösungen: stackoverflow.com/questions/36361156/…
lradacher

Antworten:


417

Sie können Ihr Objekt vergleichbar machen:

public static class MyObject implements Comparable<MyObject> {

  private Date dateTime;

  public Date getDateTime() {
    return dateTime;
  }

  public void setDateTime(Date datetime) {
    this.dateTime = datetime;
  }

  @Override
  public int compareTo(MyObject o) {
    return getDateTime().compareTo(o.getDateTime());
  }
}

Und dann sortieren Sie es, indem Sie anrufen:

Collections.sort(myList);

Manchmal möchten Sie Ihr Modell jedoch nicht ändern, z. B. wenn Sie nach verschiedenen Eigenschaften sortieren möchten. In diesem Fall können Sie einen Komparator im laufenden Betrieb erstellen:

Collections.sort(myList, new Comparator<MyObject>() {
  public int compare(MyObject o1, MyObject o2) {
      return o1.getDateTime().compareTo(o2.getDateTime());
  }
});

Dies funktioniert jedoch nur, wenn Sie sicher sind, dass dateTime zum Zeitpunkt des Vergleichs nicht null ist. Es ist ratsam, auch mit null umzugehen, um NullPointerExceptions zu vermeiden:

public static class MyObject implements Comparable<MyObject> {

  private Date dateTime;

  public Date getDateTime() {
    return dateTime;
  }

  public void setDateTime(Date datetime) {
    this.dateTime = datetime;
  }

  @Override
  public int compareTo(MyObject o) {
    if (getDateTime() == null || o.getDateTime() == null)
      return 0;
    return getDateTime().compareTo(o.getDateTime());
  }
}

Oder im zweiten Beispiel:

Collections.sort(myList, new Comparator<MyObject>() {
  public int compare(MyObject o1, MyObject o2) {
      if (o1.getDateTime() == null || o2.getDateTime() == null)
        return 0;
      return o1.getDateTime().compareTo(o2.getDateTime());
  }
});

1
Gute Antwort. Warum müssen Sie die Versionen ohne Nullprüfung einschließen? Was ist der Vorteil? Wenn der richtige Weg der zweite ist, können Sie ihn nur einschließen und die wichtigen Informationen attraktiver machen.
Amotzg

17
Zwei Gründe - Einfachheit und Schnelligkeit. Sie möchten, dass der Code so einfach wie möglich ist, und wenn Sie sicher sind, dass Ihre Eigenschaft nicht null sein sollte, möchten Sie wahrscheinlich, dass Ihr Code so schnell wie möglich fehlschlägt, wenn Sie auf null stoßen, anstatt ungültige Daten weiterzuleiten und noch weiter von der Stelle zu brechen wo ungültige Daten eingeführt wurden.
Domchi

3
Wenn o1 oder o2 null ist, geben Sie 0 zurück. // Diese Zeile kann einen Fehler verursachen, da die Rückgabe von 0 impliziert, dass sie gleich sind.
Tanjehzheng

@tanyehzheng, das ist richtig, es ist irreführend, aber beachten Sie, dass es einen Unterschied zwischen .compareTo () gibt, das zum Sortieren verwendet wird, und .equals (). Es hängt wirklich davon ab, wie Ihre Nullen beim Sortieren behandelt werden sollen.
Domchi

1
Sie sollten die Null jedes Datums separat prüfen und wie gewünscht sortieren (entweder am Anfang oder am Ende der Sequenz null sortieren). Das heißt, wenn ein Datum null und eines nicht null ist, geben Sie eine 1 oder -1 zurück. Ohne dies zu tun, werden die Nullen nicht sortiert und bleiben dort, wo sie sich vor der Sortierung in der Liste befanden.
Droozen

64

Seit Java 8 bietet die List- Schnittstelle die Sortiermethode . In Kombination mit dem Lambda- Ausdruck wäre die einfachste Lösung

// sort DateTime typed list
list.sort((d1,d2) -> d1.compareTo(d2));
// or an object which has an DateTime attribute
list.sort((o1,o2) -> o1.getDateTime().compareTo(o2.getDateTime()));
// or like mentioned by Tunaki
list.sort(Comparator.comparing(o -> o.getDateTime()));

Umgekehrte Sortierung

Java 8 enthält auch einige praktische Methoden zum umgekehrten Sortieren.

//requested by lily
list.sort(Comparator.comparing(o -> o.getDateTime()).reversed());

8
Noch besser wärelist.sort(Comparator.comparing(o -> o.getDateTime()));
Tunaki

21
Wie wäre es damit:list.sort(Comparator.comparing(MyObject::getDateTime)
Whitebrow

@Tunaki Wie mache ich die umgekehrte Sortierung?
Lilie

18

Sie können die Collections.sort-Methode verwenden. Es ist eine statische Methode. Sie übergeben ihm die Liste und einen Komparator. Es wird ein modifizierter Mergesort-Algorithmus für die Liste verwendet. Deshalb müssen Sie einen Komparator übergeben, um die Paarvergleiche durchzuführen.

Collections.sort(myList, new Comparator<MyObject> {
   public int compare(MyObject o1, MyObject o2) {
      DateTime a = o1.getDateTime();
      DateTime b = o2.getDateTime();
      if (a.lt(b)) 
        return -1;
      else if (a.lteq(b)) // it's equals
         return 0;
      else
         return 1;
   }
});

Beachten Sie, dass Sie den Komparator weglassen können, wenn myList von einem vergleichbaren Typ ist (einer, der eine vergleichbare Schnittstelle implementiert) (wie Datum, Ganzzahl oder Zeichenfolge), und die natürliche Reihenfolge verwendet wird.


1
Und gibt dies myList zurück, wenn es fertig ist oder so?

Es ändert myList. Also ist es sortiert, wenn es fertig ist
Helios

@ Schlitten: download.oracle.com/javase/6/docs/api/java/util/… , java.util.Comparator)
Helios

9
list.sort(Comparator.comparing(o -> o.getDateTime()));

Die beste Antwort IMHO von Tunaki mit Java 8 Lambda


8

Wenn MyObjectein DateTimeMitglied eine getDateTime()Methode hat, können Sie ein Element ArrayList, das MyObjectElemente enthält , nach den folgenden DateTimeObjekten sortieren :

Collections.sort(myList, new Comparator<MyObject>() {
    public int compare(MyObject o1, MyObject o2) {
        return o1.getDateTime().lt(o2.getDateTime()) ? -1 : 1;
    }
});

Was ist, wenn ich basierend auf der aktuellen Systemzeit bestellen möchte?
User3

5

So habe ich gelöst:

Collections.sort(MyList, (o1, o2) -> o1.getLastModified().compareTo(o2.getLastModified()));

Hoffe es hilft dir.


Wie kann ich es nach Datum umkehren?
Zombie

2

Mit der Einführung von Java 1.8 sind Streams sehr nützlich, um diese Art von Problemen zu lösen:

Comparator <DateTime> myComparator = (arg1, arg2) 
                -> {
                    if(arg1.lt(arg2)) 
                       return -1;
                    else if (arg1.lteq(arg2))
                       return 0;
                    else
                       return 1;
                   };

ArrayList<DateTime> sortedList = myList
                   .stream()
                   .sorted(myComparator)
                   .collect(Collectors.toCollection(ArrayList::new));

1

Alle Antworten hier waren für ein einfaches Problem unnötig komplex (zumindest für einen erfahrenen Java-Entwickler, den ich nicht bin). Ich hatte ein ähnliches Problem und bin auf diese (und andere) Lösungen gestoßen, und obwohl sie einen Hinweis lieferten, fand ich sie für einen Anfänger wie oben angegeben. Meine Lösung hängt davon ab, wo im Objekt Ihr Datum ist. In diesem Fall ist das Datum das erste Element des Objekts [], wobei dataVector die ArrayList ist, die Ihre Objekte enthält.

Collections.sort(dataVector, new Comparator<Object[]>() {
    public int compare(Object[] o1, Object[] o2) {
        return ((Date)o1[0]).compareTo(((Date)o2[0]));
    }
});

6
Wie ist Ihre Antwort weniger kompliziert oder korrekter als andere Antworten hier? Meiner Meinung nach ist die Antwort von WhiteFang32 zum Beispiel sehr ähnlich und prägnanter.
Amotzg

Ich war eine Weile weg, habe also die Antwort nicht gesehen, aber andererseits besser spät als nie. Ich denke, die Prägnanz in WhiteFangs Antwort war der Nachteil für meine (damals) unerfahrenen Java-Entwickleraugen! Die Einbeziehung der Typografie in meine Antwort war der Drahtreifen (zumindest in meinen Gedanken). Was bleibt, ist, wo Sie die Behauptung gepflückt haben, dass meine Antwort korrekter war als andere? Dampf ablassen, nehme ich an ... alles ist vergeben!
Nepaluz

Bei o.getDateTime () ging es nicht um die Eingabe, sondern um die Beschreibung eines DateTimeObjekts durch das OP, das in einem anderen Objekt enthalten ist. Wenn es nur Dateoder DateTimeObjekte waren, Comparablegab es überhaupt keine Notwendigkeit für ein Comparator.
Amotzg

Ich wollte nicht sagen, dass Ihre Antwort weniger richtig oder auf andere Weise weniger gut ist. Ich habe nur nach Informationen gesucht, um sie besser zu verstehen. Es tut mir leid, wenn es anders zu sein schien.
Amotzg

0

Dies mag eine alte Antwort sein, aber ich habe einige Beispiele aus diesem Beitrag verwendet, um einen Komparator zu erstellen, der eine Art ArrayListvon sortiertHashMap<String, String> ein Objekt nach einem in der Liste , dh dem Zeitstempel.

Ich habe diese Objekte:

ArrayList<Map<String, String>> alList = new ArrayList<Map<String, String>>();

Die Kartenobjekte sind wie folgt:

Map<String, Object> map = new HashMap<>();
        // of course this is the actual formatted date below in the timestamp
        map.put("timestamp", "MM/dd/yyyy HH:mm:ss"); 
        map.put("item1", "my text goes here");
        map.put("item2", "my text goes here");

Mit dieser Zuordnung lade ich alle meine Objekte mithilfe der alList.add(map)Funktion innerhalb einer Schleife in die Array-Liste .

Jetzt habe ich meinen eigenen Komparator erstellt:

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

 public class DateSorter implements Comparator {
     public int compare(Object firstObjToCompare, Object secondObjToCompare) {
    String firstDateString = ((HashMap<String, String>) firstObjToCompare).get("timestamp");
    String secondDateString = ((HashMap<String, String>) secondObjToCompare).get("timestamp");

    if (secondDateString == null || firstDateString == null) {
        return 0;
    }

    // Convert to Dates
    DateTimeFormatter dtf = DateTimeFormat.forPattern("MM/dd/yyyy HH:mm:ss");
    DateTime firstDate = dtf.parseDateTime(firstDateString);
    DateTime secondDate = dtf.parseDateTime(secondDateString);

    if (firstDate.isAfter(secondDate)) return -1;
    else if (firstDate.isBefore(secondDate)) return 1;
    else return 0;
    }
}

Ich kann jetzt einfach den Komparator jederzeit auf dem Array aufrufen und er sortiert mein Array, wobei ich den neuesten Zeitstempel an Position 0 (oben in der Liste) und den frühesten Zeitstempel am Ende der Liste erhalte. Neue Beiträge werden grundsätzlich an die Spitze gesetzt.

Collections.sort(alList, new DateSorter());

Dies kann jemandem helfen, weshalb ich es gepostet habe. Berücksichtigen Sie die return-Anweisungen in der Funktion compare (). Es gibt 3 Arten von Ergebnissen. Rückgabe von 0, wenn sie gleich sind, Rückgabe von> 0, wenn das erste Datum vor dem zweiten Datum liegt, und Rückgabe von <0, wenn das erste Datum nach dem zweiten Datum liegt. Wenn Sie möchten, dass Ihre Liste umgekehrt wird, wechseln Sie einfach diese beiden return-Anweisungen! Einfach =]


Ich wollte einen Kommentar dazu hinzufügen. Natürlich gibt es "NullPointerExceptions" bei der Behandlung der Array-Liste (angesichts der return 0-Anweisung). Sie müssen also damit umgehen, da jeder Fall anders ist. Zum Beispiel generiert eine Liste mit 0 Objekten eine NullPointerException oder eine Liste mit 1 Objekt!
Brandon

0

Übergeben Sie das Argument ArrayList In.

    private static void order(ArrayList<Object> list) {

    Collections.sort(list, new Comparator() {

        public int compare(Object o2, Object o1) {

            String x1 =  o1.Date;
            String x2 =  o2.Date;

                return  x1.compareTo(x2);

        }
    });
}

0

Verwenden Sie den folgenden Ansatz, um zu identifizieren, ob die Daten sortiert sind oder nicht

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd-MM-yyyy");

boolean  decendingOrder = true;
    for(int index=0;index<date.size() - 1; index++) {
        if(simpleDateFormat.parse(date.get(index)).getTime() < simpleDateFormat.parse(date.get(index+1)).getTime()) {
            decendingOrder = false;
            break;
        }
    }
    if(decendingOrder) {
        System.out.println("Date are in Decending Order");
    }else {
        System.out.println("Date not in Decending Order");
    }       
}   

1
Es scheint die Frage nicht zu beantworten. Und bitte bringen Sie den Jungen nicht bei, die lange veraltete und notorisch problematische SimpleDateFormatKlasse zu benutzen . Zumindest nicht als erste Option. Und das nicht ohne Vorbehalt. Heute haben wir java.timedie moderne Java-API für Datum und Uhrzeit und ihre DateTimeFormatter.
Ole VV

0

Die Date-Klasse implementiert bereits die Comparator-Schnittstelle. Angenommen, Sie haben die folgende Klasse:

public class A {

    private Date dateTime;

    public Date getDateTime() {
        return dateTime;
    }

    .... other variables

}

Angenommen, Sie haben eine Liste von A-Objekten List<A> aList, die Sie einfach mit der Stream-API von Java 8 sortieren können (Ausschnitt unten):

import java.util.Comparator;
import java.util.stream.Collectors;

...

aList = aList.stream()
        .sorted(Comparator.comparing(A::getDateTime))
        .collect(Collectors.toList())

-1

Zukünftige Betrachter, ich denke, dies ist die einfachste Lösung. Wenn Ihr Modell ein Datum vom Typ Zeichenfolge enthält (z. B. "2020-01-01 10:00:00"), schreiben Sie einfach die folgende Zeile, um die Daten nach absteigendem Datum zu sortieren vom neuesten zum ältesten:

Collections.sort(messages, (o1, o2) -> o2.getMessageDate().compareTo(o1.getMessageDate()));
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.