Sắp xếp các đối tượng trong ArrayList theo ngày?


149

Mỗi ví dụ tôi tìm thấy là về việc thực hiện theo thứ tự bảng chữ cái này, trong khi tôi cần các yếu tố của mình được sắp xếp theo ngày.

ArrayList của tôi chứa các đối tượng mà một trong các datamembers là đối tượng DateTime. Trên DateTime tôi có thể gọi các chức năng:

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

Vì vậy, để so sánh tôi có thể làm một cái gì đó như:

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

Tôi nên làm gì bên trong khối if?


3
Tôi đã đăng giải pháp nhưng nếu bạn muốn hiểu rõ hơn về việc đặt hàng, bạn nên đọc về các thuật toán đặt hàng (bubbleort, mergesort, quicksort, v.v.).
helios

Cảm ơn, tôi sẽ xem xét những thứ đó, tôi không biết gì về cách sắp xếp

Một số giải pháp Java 1.8 hữu ích có thể được tìm thấy trong luồng này: stackoverflow.com/questions/36361156/ory
lradacher 26/03/18

Câu trả lời:


417

Bạn có thể làm cho đối tượng của bạn có thể so sánh:

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

Và sau đó bạn sắp xếp nó bằng cách gọi:

Collections.sort(myList);

Tuy nhiên, đôi khi bạn không muốn thay đổi mô hình của mình, như khi bạn muốn sắp xếp trên một số thuộc tính khác nhau. Trong trường hợp đó, bạn có thể tạo bộ so sánh nhanh chóng:

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

Tuy nhiên, cách trên chỉ hoạt động nếu bạn chắc chắn rằng dateTime không rỗng tại thời điểm so sánh. Thật là khôn ngoan khi xử lý null cũng như tránh NullPulumExceptions:

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

Hoặc trong ví dụ thứ hai:

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
Câu trả lời tốt. Tại sao bạn cần bao gồm các phiên bản mà không kiểm tra null? Lợi thế là gì? Nếu cách chính xác là cách thứ hai, bạn chỉ có thể đưa nó vào và làm cho thông tin quan trọng trở nên hấp dẫn hơn.
amotzg

17
Hai lý do - đơn giản và thất bại nhanh chóng. Bạn muốn mã càng đơn giản càng tốt và nếu bạn chắc chắn rằng tài sản của bạn không phải là null thì có lẽ bạn muốn mã của mình bị lỗi càng sớm càng tốt nếu bạn gặp null, thay vào đó hãy truyền dữ liệu không hợp lệ và phá vỡ hơn nữa từ vị trí nơi dữ liệu không hợp lệ được giới thiệu.
Domchi

3
nếu o1 hoặc o2 là null, trả về 0; // dòng này có thể gây ra lỗi khi trả về 0 ngụ ý rằng chúng bằng nhau.
tanyehzheng

@tanyehzheng, điều đó đúng, nó gây hiểu nhầm, nhưng lưu ý rằng có một sự khác biệt giữa .compareTo () được sử dụng để sắp xếp và .equals (). Nó thực sự phụ thuộc vào cách bạn muốn null của bạn được xử lý trong khi sắp xếp.
Domchi

1
Bạn nên kiểm tra riêng từng ngày của null và sắp xếp theo ý muốn (có thể là null ở đầu hoặc cuối chuỗi). Nghĩa là, nếu một ngày là null và một ngày không null, hãy trả về 1 hoặc -1. Không làm điều đó, các null không được sắp xếp và vẫn ở bất cứ nơi nào chúng có trong danh sách trước khi sắp xếp.
droozen

64

Vì Java 8, giao diện List cung cấp phương thức sắp xếp . Kết hợp với biểu thức lambda , giải pháp đơn giản nhất sẽ là

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

Sắp xếp ngược

Java 8 cũng đi kèm với một số phương thức tiện dụng để sắp xếp ngược lại.

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

8
Thậm chí tốt hơn sẽ làlist.sort(Comparator.comparing(o -> o.getDateTime()));
Tunaki

21
Làm thế nào về điều này:list.sort(Comparator.comparing(MyObject::getDateTime)
whitebr

@Tunaki làm thế nào để phân loại ngược?
hoa huệ

18

Bạn có thể sử dụng phương thức Collections.sort. Đó là một phương pháp tĩnh. Bạn vượt qua nó danh sách và một bộ so sánh. Nó sử dụng một thuật toán hợp nhất sửa đổi trong danh sách. Đó là lý do tại sao bạn phải vượt qua nó một bộ so sánh để thực hiện so sánh cặp.

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

Lưu ý rằng nếu myList thuộc loại có thể so sánh (loại có giao diện so sánh) (như Ngày, Số nguyên hoặc Chuỗi), bạn có thể bỏ qua bộ so sánh và thứ tự tự nhiên sẽ được sử dụng.


1
Và điều này có trả lại myList khi nó được thực hiện hoặc một cái gì đó tương tự không?

Nó sửa đổi myList. Vì vậy, nó được sắp xếp khi nó kết thúc
helios

@Sled: download.oracle.com/javase/6/docs/api/java/util/ Khăn , java.util.Comparator)
helios

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

Câu trả lời hay nhất IMHO từ Tunaki bằng Java 8 lambda


8

Cho MyObjectrằng có một DateTimethành viên với một getDateTime()phương thức, bạn có thể sắp xếp một phần tử ArrayListcó chứa MyObjectcác phần tử theo các DateTimeđối tượng như thế này:

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

Điều gì xảy ra nếu tôi muốn đặt hàng dựa trên thời gian hệ thống hiện tại.
dùng3

5

Đây là cách tôi giải quyết:

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

Hy vọng nó sẽ giúp bạn.


Làm thế nào để đảo ngược nó theo ngày?
Zombie

2

Với việc giới thiệu Java 1.8, các luồng rất hữu ích trong việc giải quyết loại vấn đề này:

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

Tất cả các câu trả lời ở đây tôi thấy là phức tạp không cần thiết cho một vấn đề đơn giản (ít nhất là đối với một nhà phát triển java có kinh nghiệm, mà tôi thì không). Tôi đã có một vấn đề tương tự và tình cờ tìm ra giải pháp này (và các giải pháp khác), và mặc dù chúng đã cung cấp một con trỏ, cho một người mới bắt đầu tôi đã tìm thấy như đã nêu ở trên. Giải pháp của tôi, tùy thuộc vào vị trí trong Đối tượng mà Ngày của bạn, trong trường hợp này, ngày là thành phần đầu tiên của Đối tượng [] trong đó dataVector là ArrayList chứa Đối tượng của bạn.

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

6
Làm thế nào là câu trả lời của bạn ít phức tạp hơn hoặc chính xác hơn các câu trả lời khác ở đây? Theo ý kiến ​​của tôi, ví dụ câu trả lời của WhiteFang32 rất giống nhau và súc tích hơn.
amotzg

Đã xa một thời gian, vì vậy không thấy phản hồi, nhưng rồi một lần nữa, muộn còn hơn không. Tôi nghĩ rằng sự đồng nhất trong câu trả lời của WhiteFang là nhược điểm của nó đối với nhà phát triển java thiếu kinh nghiệm (lúc đó) của tôi! Sự bao gồm của typecasting trong phản ứng của tôi là móc sắt (ít nhất là trong tâm trí của tôi). Những gì còn lại là nơi bạn đưa ra tuyên bố rằng câu trả lời của tôi là chính xác hơn những người khác? Buông hơi tôi cho rằng .. tất cả đều được tha thứ!
Nepaluz

O.getDateTime () không phải về cách gõ, mà là về mô tả của OP về một DateTimeđối tượng được chứa bên trong một đối tượng khác. Nếu đó chỉ là Datehoặc DateTimecác đối tượng Comparablekhông có nhu cầu Comparatorở nơi đầu tiên.
amotzg

Không có nghĩa là nói câu trả lời của bạn là ít chính xác hoặc ít tốt hơn. Tôi chỉ là tôi tìm kiếm thông tin để giúp tôi hiểu rõ hơn về nó. Tôi xin lỗi nếu nó có vẻ khác.
amotzg

0

Đây có thể là một phản ứng cũ nhưng tôi đã sử dụng một số ví dụ từ bài này để tạo ra một so sánh rằng sẽ sắp xếp một ArrayListsố HashMap<String, String>bởi một đối tượng trong danh sách, đó là dấu thời gian.

Tôi có những đối tượng này:

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

Các đối tượng bản đồ như sau:

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

Ánh xạ đó là những gì tôi sử dụng để tải tất cả các đối tượng của mình vào danh sách mảng, sử dụng alList.add(map)hàm, trong một vòng lặp.

Bây giờ, tôi đã tạo ra bộ so sánh của riêng mình:

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

Bây giờ tôi có thể gọi Trình so sánh bất cứ lúc nào trên mảng và nó sẽ sắp xếp mảng của tôi, đưa cho tôi dấu thời gian mới nhất ở vị trí 0 (đầu danh sách) và dấu thời gian sớm nhất ở cuối danh sách. Bài viết mới được đưa lên đầu về cơ bản.

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

Điều này có thể giúp ai đó ra ngoài, đó là lý do tại sao tôi đăng nó. Hãy xem xét các câu lệnh return trong hàm so sánh (). Có 3 loại kết quả. Trả về 0 nếu chúng bằng nhau, trả về> 0 nếu ngày đầu tiên trước ngày thứ hai và trả về <0 nếu ngày đầu tiên là sau ngày thứ hai. Nếu bạn muốn danh sách của bạn bị đảo ngược, thì chỉ cần chuyển hai câu trả về đó! Đơn giản =]


Tôi muốn thêm một bình luận về điều này. Tất nhiên, có "NullPulumExceptions" khi xử lý danh sách mảng (đưa ra câu lệnh return 0). Vì vậy, bạn sẽ phải xử lý chúng vì mỗi trường hợp sẽ khác nhau. Ví dụ, một danh sách có 0 đối tượng sẽ tạo ra một NullPulumException hoặc một danh sách có 1 đối tượng!
Brandon

0

Vượt qua ArrayList Trong đối số.

    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

Sử dụng cách tiếp cận dưới đây để xác định ngày có sắp xếp hay không

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
Nó dường như không trả lời câu hỏi. Và xin đừng dạy những người trẻ tuổi sử dụng SimpleDateFormatlớp học lỗi thời và nổi tiếng là rắc rối . Ít nhất không phải là lựa chọn đầu tiên. Và không phải không có bất kỳ đặt phòng. Ngày nay chúng ta có rất nhiều thứ tốt hơn java.time, API ngày và thời gian Java hiện đại và của nó DateTimeFormatter.
Ole VV

0

Lớp Date đã thực hiện giao diện So sánh. Giả sử bạn có lớp dưới đây:

public class A {

    private Date dateTime;

    public Date getDateTime() {
        return dateTime;
    }

    .... other variables

}

Và giả sử bạn có một danh sách các đối tượng A List<A> aList, bạn có thể dễ dàng sắp xếp nó với API luồng của Java 8 (đoạn dưới đây):

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

...

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

-1

Người xem trong tương lai, tôi nghĩ đây là giải pháp đơn giản nhất, nếu mô hình của bạn chứa ngày loại chuỗi (ví dụ: "2020-01-01 10:00:00"), sau đó chỉ cần viết dòng sau để sắp xếp dữ liệu theo ngày giảm dần từ mới nhất đến cũ nhất:

Collections.sort(messages, (o1, o2) -> o2.getMessageDate().compareTo(o1.getMessageDate()));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.