Urutkan objek di ArrayList menurut tanggal?

149

Setiap contoh yang saya temukan adalah tentang melakukan hal ini secara alfabet, sedangkan elemen-elemen saya perlu diurutkan berdasarkan tanggal.

ArrayList saya berisi objek yang salah satu datamembersnya adalah objek DateTime. Pada DateTime saya dapat memanggil fungsi:

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

Jadi untuk membandingkan saya bisa melakukan sesuatu seperti:

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

Apa yang harus saya lakukan di dalam blok if?

Trilarion
sumber
3
Saya memposting solusinya tetapi jika Anda ingin mendapatkan wawasan tentang pemesanan Anda harus membaca tentang algoritma pemesanan (bubblesort, mergesort, quicksort, dll).
helios
Terima kasih, saya akan melihat pada mereka, saya tidak tahu apa-apa tentang penyortiran
Beberapa solusi Java 1.8 yang berguna dapat ditemukan di utas ini: stackoverflow.com/questions/36361156/…
lradacher

Jawaban:

418

Anda dapat membuat objek Anda sebanding:

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

Dan kemudian Anda mengurutkannya dengan menelepon:

Collections.sort(myList);

Namun terkadang Anda tidak ingin mengubah model Anda, seperti ketika Anda ingin mengurutkan pada beberapa properti yang berbeda. Dalam hal ini, Anda dapat membuat komparator dengan cepat:

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

Namun, hal di atas hanya berfungsi jika Anda yakin bahwa dateTime tidak nol pada saat perbandingan. Adalah bijaksana untuk menangani null juga untuk menghindari NullPointerExceptions:

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

Atau dalam contoh kedua:

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());
  }
});
Domchi
sumber
1
Jawaban yang bagus. Mengapa Anda perlu menyertakan versi tanpa pemeriksaan nol? Apa keuntungannya? Jika cara yang benar adalah yang kedua, Anda hanya bisa memasukkannya dan membuat info penting lebih menarik.
amotzg
17
Dua alasan - kesederhanaan dan kegagalan-cepat. Anda ingin kode sesederhana mungkin, dan jika Anda yakin bahwa properti Anda tidak boleh nol, Anda mungkin ingin kode Anda gagal sesegera mungkin jika Anda menemukan nol, alih-alih meneruskan data yang tidak valid dan memecah lebih jauh dari tempat itu di mana data yang tidak valid diperkenalkan.
Domchi
3
jika o1 atau o2 adalah nol, kembalikan 0; // baris ini dapat menyebabkan bug karena mengembalikan 0 menyiratkan bahwa mereka sama.
tanyehzheng
@tanyehzheng, itu benar, itu menyesatkan, tetapi perhatikan bahwa ada perbedaan antara .compareTo () yang digunakan untuk menyortir dan .equals (). Ini benar-benar tergantung pada bagaimana Anda ingin null Anda ditangani selama penyortiran.
Domchi
1
Anda harus memeriksa nol setiap tanggal secara terpisah dan mengurutkan sesuai keinginan (baik jenis nol pada awal atau akhir urutan). Yaitu, jika satu tanggal adalah nol dan satu bukan nol, kembalikan 1 atau -1. Tanpa melakukan itu, nol tidak diurutkan dan tetap di mana pun mereka berada dalam daftar sebelum diurutkan.
droozen
64

Karena Java 8 antarmuka Daftar menyediakan metode pengurutan . Dikombinasikan dengan ekspresi lambda solusi termudah adalah

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

Reverse sorting

Java 8 hadir juga dengan beberapa metode praktis untuk pemilahan terbalik.

//requested by lily
list.sort(Comparator.comparing(o -> o.getDateTime()).reversed());
Paul Wasilewski
sumber
8
Bahkan lebih baiklist.sort(Comparator.comparing(o -> o.getDateTime()));
Tunaki
21
Bagaimana dengan ini:list.sort(Comparator.comparing(MyObject::getDateTime)
whitebrow
@Tunaki bagaimana cara melakukan sortir terbalik?
Lily
18

Anda dapat menggunakan metode Collections.sort. Ini metode statis. Anda memberikan daftar dan pembanding. Ini menggunakan algoritma mergesort yang dimodifikasi di atas daftar. Itu sebabnya Anda harus memberikannya pembanding untuk melakukan perbandingan pasangan.

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

Perhatikan bahwa jika myList adalah tipe yang sebanding (yang mengimplementasikan antarmuka Sebanding) (seperti Date, Integer atau String) Anda dapat menghilangkan komparator dan pemesanan alami akan digunakan.

helios
sumber
1
Dan apakah ini mengembalikan myList ketika selesai atau sesuatu seperti itu?
Ini memodifikasi myList. Jadi disortir saat selesai
helios
@Sled: download.oracle.com/javase/6/docs/api/java/util/… , java.util.Comparator)
helios
9
list.sort(Comparator.comparing(o -> o.getDateTime()));

Jawaban IMHO terbaik dari Tunaki menggunakan Java 8 lambda

Kucing Stimpson
sumber
8

Mengingat MyObjectmemiliki DateTimeanggota dengan getDateTime()metode, Anda bisa mengurutkan ArrayListyang berisi MyObjectelemen dengan DateTimeobjek seperti ini:

Collections.sort(myList, new Comparator<MyObject>() {
    public int compare(MyObject o1, MyObject o2) {
        return o1.getDateTime().lt(o2.getDateTime()) ? -1 : 1;
    }
});
WhiteFang34
sumber
Bagaimana jika saya ingin memesan berdasarkan waktu sistem saat ini.
Pengguna3
5

Inilah cara saya memecahkan:

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

Semoga ini bisa membantu Anda.

Igor Escobar
sumber
bagaimana cara mengembalikannya berdasarkan tanggal?
Zombie
2

Dengan diperkenalkannya Java 1.8, stream sangat berguna dalam memecahkan masalah seperti ini:

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));
Tinki
sumber
1

Semua jawaban di sini saya temukan sangat kompleks untuk masalah sederhana (setidaknya untuk pengembang java yang berpengalaman, yang saya tidak). Saya memiliki masalah yang sama dan kebetulan pada solusi ini (dan lainnya), dan meskipun mereka memberikan pointer, untuk pemula saya menemukan seperti yang dinyatakan di atas. Solusi saya, tergantung pada di mana di Object Anda Date, dalam hal ini, date adalah elemen pertama dari Object [] di mana dataVector adalah ArrayList yang berisi Objects Anda.

Collections.sort(dataVector, new Comparator<Object[]>() {
    public int compare(Object[] o1, Object[] o2) {
        return ((Date)o1[0]).compareTo(((Date)o2[0]));
    }
});
Nepaluz
sumber
6
Bagaimana jawaban Anda kurang rumit atau lebih benar daripada jawaban lain di sini? Menurut pendapat saya, jawaban WhiteFang32 misalnya sangat mirip dan lebih ringkas.
amotzg
Sudah pergi untuk sementara waktu, jadi tidak melihat respons, tapi sekali lagi, lebih baik terlambat daripada tidak sama sekali. Saya pikir keringkasan dalam jawaban WhiteFang adalah kelemahannya bagi mata pengembang java saya yang belum berpengalaman! Dimasukkannya typecasting dalam respons saya adalah penentu (setidaknya dalam pikiran saya kemudian). Apa yang tersisa adalah tempat Anda memetik klaim bahwa jawaban saya lebih benar daripada yang lain? Melepaskan uap saya kira .. semua dimaafkan!
Nepaluz
The o.getDateTime () bukan tentang mengetik, ini adalah tentang deskripsi OP dari suatu DateTimeobjek yang terkandung di dalam objek lain. Jika itu hanya Dateatau DateTimebenda yang Comparableada tidak perlu untuk Comparatordi tempat pertama.
amotzg
Tidak bermaksud mengatakan jawaban Anda kurang benar atau sebaliknya kurang baik. Saya hanya saya mencari info untuk membantu saya lebih memahaminya. Saya minta maaf jika tampaknya sebaliknya.
amotzg
0

Ini mungkin sebuah respon lama tapi saya menggunakan beberapa contoh dari posting ini untuk membuat pembanding yang akan mengurutkan ArrayListdari HashMap<String, String>oleh satu objek dalam daftar, bahwa menjadi timestamp.

Saya punya benda-benda ini:

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

Objek peta adalah sebagai berikut:

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

Pemetaan itu adalah apa yang saya gunakan untuk memuat semua objek saya ke dalam daftar array, menggunakan alList.add(map)fungsi, dalam satu lingkaran.

Sekarang, saya membuat pembanding sendiri:

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

Saya sekarang dapat memanggil Pembanding kapan saja pada array dan itu akan mengurutkan array saya, memberi saya cap waktu terbaru di posisi 0 (atas daftar) dan cap waktu paling awal di akhir daftar. Pada dasarnya posting baru ditempatkan di atas.

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

Ini dapat membantu seseorang, itulah sebabnya saya mempostingnya. Mempertimbangkan pernyataan pengembalian dalam fungsi compare (). Ada 3 jenis hasil. Mengembalikan 0 jika sama, mengembalikan> 0 jika kencan pertama sebelum kencan kedua dan mengembalikan <0 jika kencan pertama setelah kencan kedua. Jika Anda ingin daftar Anda dibalik, maka alihkan kedua pernyataan pengembalian itu! Sederhana =]

Brandon
sumber
Saya ingin menambahkan komentar tentang ini. Tentu saja ada "NullPointerExceptions" saat menangani daftar array (diberikan pernyataan 0 pengembalian). Jadi, Anda harus menanganinya karena setiap kasing akan berbeda. Misalnya daftar dengan 0 objek akan menghasilkan NullPointerException, atau daftar dengan 1 objek!
Brandon
0

Lewati argumen 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);

        }
    });
}
Senghani Maulik
sumber
0

Gunakan pendekatan di bawah ini untuk mengidentifikasi tanggal apakah sortir atau bukan

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");
    }       
}   
Vikas Rathour
sumber
1
Sepertinya tidak menjawab pertanyaan. Dan tolong jangan mengajari anak-anak untuk menggunakan kelas yang sudah lama usang dan terkenal merepotkan SimpleDateFormat. Setidaknya bukan sebagai opsi pertama. Dan bukan tanpa reservasi apa pun. Hari ini kita memiliki jauh lebih baik java.time, API tanggal dan waktu Jawa modern dan DateTimeFormatter.
Ole VV
0

Kelas Date sudah mengimplementasikan antarmuka Comparator. Dengan asumsi Anda memiliki kelas di bawah ini:

public class A {

    private Date dateTime;

    public Date getDateTime() {
        return dateTime;
    }

    .... other variables

}

Dan katakanlah Anda memiliki daftar objek A sebagai List<A> aList, Anda dapat dengan mudah mengurutkannya dengan API aliran Java 8 (cuplikan di bawah):

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

...

aList = aList.stream()
        .sorted(Comparator.comparing(A::getDateTime))
        .collect(Collectors.toList())
Anthony Anyanwu
sumber
-1

Pemirsa di masa depan, saya pikir ini adalah solusi paling sederhana, jika model Anda berisi tanggal tipe string ("2020-01-01 10:00:00" misalnya), maka cukup tulis baris berikut untuk mengurutkan data berdasarkan tanggal turun dari terbaru ke terlama:

Collections.sort(messages, (o1, o2) -> o2.getMessageDate().compareTo(o1.getMessageDate()));
Hamza Al-Omari
sumber