ArrayList'teki nesneler tarihe göre sıralansın mı?


154

Bulduğum her örnek, bunu alfabetik olarak yapmakla ilgili, ancak öğelerimin tarihe göre sıralanmasına ihtiyacım var.

ArrayList, veri üyelerinden birinin DateTime nesnesi olduğu nesneleri içerir. DateTime'da işlevleri çağırabilirim:

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

Yani karşılaştırmak için şöyle bir şey yapabilirim:

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

İf bloğunun içinde ne yapmalıyım?


3
Çözümü yayınladım, ancak sipariş verme hakkında bir fikir edinmek istiyorsanız, sipariş algoritmaları hakkında okumalısınız (bubbleort, birleştirme, hızlı sıralama, vb.).
helios

Teşekkürler, bunlara bir bakacağım, sıralama hakkında hiçbir şey bilmiyorum

Bu ileti dizisinde birkaç yararlı Java 1.8 çözümü bulunabilir: stackoverflow.com/questions/36361156/…
lradacher

Yanıtlar:


428

Nesnenizi karşılaştırılabilir hale getirebilirsiniz:

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

Ve sonra arayarak sıralayın:

Collections.sort(myList);

Ancak bazen, birkaç farklı özelliği sıralamak istediğinizde olduğu gibi modelinizi değiştirmek istemezsiniz. Bu durumda, anında karşılaştırıcı oluşturabilirsiniz:

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

Ancak, yukarıdaki yalnızca karşılaştırma sırasında dateTime öğesinin boş olmadığından eminseniz çalışır. NullPointerExceptions'dan kaçınmak için null'u da işlemek akıllıca olacaktır:

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

Veya ikinci örnekte:

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
İyi cevap. Neden null denetimi olmadan sürümleri eklemeniz gerekiyor? Avantajı nedir? Doğru yol ikinci ise, yalnızca onu ekleyebilir ve önemli bilgileri daha çekici hale getirebilirsiniz.
amotzg

17
İki neden - basitlik ve hızlı hata. Kodun olabildiğince basit olmasını istersiniz ve mülkünüzün boş olmaması gerektiğinden eminseniz, büyük olasılıkla null ile karşılaşırsanız kodunuzun mümkün olan en kısa sürede başarısız olmasını istersiniz, bunun yerine geçersiz verileri iletmek ve yerden daha da uzaklaşmak geçersiz verilerin tanıtıldığı yer.
Domchi

3
o1 veya o2 null ise, 0 döndür; // 0 döndürmek eşit olduklarını ima ettiğinden bu satır hataya neden olabilir.
tanyehzheng

@tanyehzheng, bu doğru, yanıltıcıdır, ancak sıralama için kullanılan .compareTo () ve .equals () arasında bir fark olduğuna dikkat edin. Bu gerçekten, sıralama sırasında boş değerlerin nasıl işlenmesini istediğinize bağlıdır.
Domchi

1
Her bir tarihin null değerini ayrı ayrı kontrol etmeli ve istediğiniz gibi sıralamanız gerekir (dizinin başında veya sonunda boş sıralama). Diğer bir deyişle, bir tarih boşsa ve biri boş değilse, 1 veya -1 döndür. Bunu yapmadan, boş değerler sıralanmaz ve sıralamadan önce listede oldukları yerde kalırlar.
droozen

68

Java 8'den beri Liste arabirimi sıralama yöntemini sağlar. İle birlikte lambda ifade kolay çözüm olurdu

// 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()));

Ters sıralama

Java 8 ayrıca ters sıralama için bazı kullanışlı yöntemlerle birlikte gelir.

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

8
Daha da iyisilist.sort(Comparator.comparing(o -> o.getDateTime()));
Tunaki

24
Buna ne dersin:list.sort(Comparator.comparing(MyObject::getDateTime)
whitebrow

@Tunaki ters sıralama nasıl yapılır?
lily

@lily, Collections.sort (liste, Collections.reverseOrder ());
sanghavi7

18

Collections.sort yöntemini kullanabilirsiniz. Statik bir yöntemdir. Listeyi ve bir karşılaştırıcıyı iletirsiniz. Liste üzerinde değiştirilmiş bir birleştirme algoritması kullanır. Bu nedenle, çift karşılaştırmaları yapmak için ona bir karşılaştırıcı vermelisiniz.

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

MyList karşılaştırılabilir bir türdeyse (Karşılaştırılabilir arabirimi uygulayan biri) (Tarih, Tamsayı veya Dize gibi), karşılaştırıcıyı atlayabileceğinizi ve doğal sıralamanın kullanılacağını unutmayın.


1
Ve tamamlandığında veya bunun gibi bir şey olduğunda bu myList'i döndürür mü?

MyList'i değiştirir. Yani bittiğinde sıralandı
helios


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

Java 8 lambda kullanarak Tunaki'den en iyi cevap IMHO


8

Verilen MyObjectbir olduğunu DateTimebir elemanını getDateTime()yöntemiyle, bir sıralayabilirsiniz ArrayListiçerdiğini MyObjecttarafından elemanlarını DateTimeböyle nesneler:

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

Mevcut sistem saatine göre sipariş vermek istersem ne olur?
Kullanıcı3

6

Ben böyle çözdüm:

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

Umarım sana yardımcı olur.


tarihe göre nasıl tersine çevirebilirim?
Zombie

2

Java 1.8'in piyasaya sürülmesiyle, akışlar bu tür sorunları çözmede çok kullanışlıdır:

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

Buradaki tüm cevaplar basit bir problem için gereksiz yere karmaşık buldum (en azından tecrübeli bir java geliştiricisi için, ki ben değilim). Benzer bir sorun yaşadım ve bu (ve diğer) çözümlere tesadüfen rastladım ve yukarıda belirtildiği gibi yeni başlayanlar için bir gösterge sağlamalarına rağmen. Benim çözümüm, Tarihinizin Nesnesinde nerede olduğuna bağlıdır, bu durumda tarih, DataVector'ın Nesnelerinizi içeren ArrayList olduğu Object [] öğesinin ilk öğesidir .

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

6
Cevabınız nasıl daha az karmaşık veya buradaki diğer cevaplardan daha doğru? Bana göre, örneğin WhiteFang32'nin cevabı çok benzer ve daha özlü.
amotzg

Bir süredir uzaktaydı, bu yüzden yanıtı görmedim, ama sonra tekrar, hiç olmamasından iyidir. WhiteFang'in cevabındaki özlülüğün, benim (o zamanlar) deneyimsiz java geliştirici gözlerimin dezavantajı olduğunu düşünüyorum! Cevabıma tip dökümünün dahil edilmesi (en azından aklımda) en önemli noktaydı. Geriye kalan, cevabımın diğerlerinden daha doğru olduğu iddiasını çıkardığınız yer mi? Buharı bırakmak sanırım .. her şey affedildi!
Nepal

O.getDateTime () yazmakla ilgili değildi, OP'nin DateTimebaşka bir nesnenin içinde bulunan bir nesneye ilişkin açıklamasıyla ilgiliydi . Sadece Dateya da var olan DateTimenesneler olsaydı , ilk etapta Comparablea'ya gerek yoktu Comparator.
amotzg

Cevabınızın daha az doğru veya daha az iyi olduğunu söylemek istemedim. Daha iyi anlamama yardımcı olacak bilgi arıyordum. Aksi gibi göründüyse özür dilerim.
amotzg

1

Tarihlerin sıralı olup olmadığını belirlemek için aşağıdaki yaklaşımı kullanın

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
Soruyu yanıtlamıyor gibi görünüyor. Ve lütfen gençlere uzun süredir modası geçmiş ve herkesin bildiği gibi sorunlu SimpleDateFormatsınıfı kullanmayı öğretmeyin . En azından ilk seçenek olarak değil. Ve herhangi bir çekincesiz değil. Bugün java.time, modern Java tarih ve saat API'sinde ve onun DateTimeFormatter.
Ole VV

0

Bu eski bir yanıt olabilir, ancak bu gönderideki bazı örnekleri, bir karşılaştırıcı oluşturmak için kullandım ArrayList.HashMap<String, String> zaman damgası olan bu listedeki bir obje tarafından.

Bu nesnelere sahibim:

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

Harita nesneleri aşağıdaki gibidir:

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

Bu eşleme, tüm nesnelerimi dizi listesine yüklemek için kullandığım şeydir. alList.add(map) bir döngü içinde işlevi .

Şimdi, kendi karşılaştırıcımı yarattım:

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

Artık dizide herhangi bir zamanda Karşılaştırıcıyı arayabilirim ve dizimi sıralayarak bana 0 konumundaki en son zaman damgasını (listenin en üstünde) ve listenin sonundaki en erken zaman damgasını verir. Yeni gönderiler temelde en üst sıraya yerleştirilir.

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

Bu birisine yardımcı olabilir, bu yüzden onu gönderdim. Compare () işlevindeki dönüş ifadelerini dikkate alın. 3 tür sonuç vardır. Eşitse 0 döndürür, ilk tarih ikinci tarihten önceyse> 0 döndürür ve ilk tarih ikinci tarihten sonraysa <0 döndürür. Listenizin tersine çevrilmesini istiyorsanız, o zaman bu iki dönüş ifadesini değiştirin! Basit =]


Buna bir yorum eklemek istedim. Elbette dizi listesini işlerken "NullPointerExceptions" vardır (dönüş 0 ifadesi verildiğinde). Bu nedenle, her durum farklı olacağından bunları ele almanız gerekecek. Örneğin, 0 nesneli bir liste bir NullPointerException veya 1 nesneli bir liste oluşturacaktır!
Brandon

0

ArrayList In bağımsız değişkenini iletin.

    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

Date sınıfı, Comparator arabirimini zaten uyguluyor. Aşağıdaki sınıfa sahip olduğunuzu varsayarsak:

public class A {

    private Date dateTime;

    public Date getDateTime() {
        return dateTime;
    }

    .... other variables

}

Diyelim ki bir A nesnesi listeniz var, çünkü List<A> aListbunu Java 8'in akış API'si ile kolayca sıralayabilirsiniz (aşağıdaki snippet):

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

...

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

0

İşte bunu nasıl başardığımın cevabı:

Mylist.sort(Comparator.comparing(myClass::getStarttime));

-1

Gelecekteki izleyiciler, bence bu en basit çözüm, eğer modeliniz bir dize türü tarih içeriyorsa (örneğin "2020-01-01 10:00:00"), o zaman verileri tarihe göre azalan tarihe göre sıralamak için aşağıdaki satırı yazmanız yeterlidir. en yeniden en eskiye:

Collections.sort(messages, (o1, o2) -> o2.getMessageDate().compareTo(o1.getMessageDate()));
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.