Сортувати об’єкти в ArrayList за датою?


149

Кожен знайдений мені приклад - це робити в алфавітному порядку, тоді як мені потрібні елементи, відсортовані за датою.

Мій ArrayList містить об'єкти, на яких одна з членів даних є об'єктом DateTime. У DateTime я можу викликати функції:

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

Тож для порівняння я міг би зробити щось на кшталт:

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

Що мені робити всередині блоку if?


3
Я розмістив рішення, але якщо ви хочете ознайомитись із замовленням, вам слід ознайомитися з алгоритмами замовлення (бульборт, mergesort, quicksort тощо).
— геліос

Дякую, я перегляну ці, я нічого не знаю про сортування

Кілька корисних Java 1.8 рішення можна знайти в цій темі: stackoverflow.com/questions/36361156 / ...
— lradacher

Відповіді:


417

Ви можете зробити об'єкт порівнянним:

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

А потім ви сортуєте це, зателефонувавши:

Collections.sort(myList);

Однак іноді ви не хочете змінювати свою модель, як, наприклад, коли потрібно сортувати декілька різних властивостей. У цьому випадку ви можете створити компаратор на льоту:

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

Однак вищезазначене працює лише в тому випадку, якщо ви впевнені, що dateTime не є нульовим на момент порівняння. Доцільно також обробляти null, щоб уникнути 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());
  }
}

Або у другому прикладі:

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
Хороша відповідь. Чому потрібно включати версії без нульової перевірки? Яка перевага? Якщо правильний шлях є другим, ви можете лише включити його та зробити важливу інформацію більш привабливою.
— amotzg

17
Дві причини - простота і невдача. Ви хочете, щоб код був максимально простим, і якщо ви впевнені, що ваше майно не повинно бути недійсним, ви, мабуть, хочете, щоб ваш код вийшов з ладу якнайшвидше, якщо ви зіткнулися з нулем, замість цього передайте недійсні дані та ще більше відірвіться від місця де були введені недійсні дані
— Домчі

3
якщо o1 або o2 є нульовим, поверніть 0; // Цей рядок може спричинити помилку, оскільки повернення 0 означає, що вони рівні.
— tanyehzheng

@tanyehzheng, це правильно, це вводить в оману, але зауважте, що існує різниця між .compareTo (), який використовується для сортування, і .equals (). Це дійсно залежить від того, як ви хочете, щоб ваші нулі оброблялися під час сортування.
— Домчі

1
Ви повинні перевірити нульову дату кожної дати окремо та сортувати за бажанням (будь-які нульові сортування на початку чи в кінці послідовності). Тобто, якщо одна дата є нульовою, а одна - недійсною, поверніть 1 або -1. Не роблячи цього, нулі не сортуються і залишаються там, де вони траплялися, у списку перед сортуванням.
— droozen

64

Оскільки Java 8, інтерфейс List забезпечує метод сортування . У поєднанні з виразом лямбда було б найпростішим рішенням

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

Зворотне сортування

Java 8 також пропонує деякі зручні методи зворотного сортування.

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

8
Ще краще було бlist.sort(Comparator.comparing(o -> o.getDateTime()));
— Тунакі

21
Як щодо цього:list.sort(Comparator.comparing(MyObject::getDateTime)
— біла

@Tunaki як зробити зворотне сортування?
— лілія

18

Можна використовувати метод Collections.sort. Це статичний метод. Ви передаєте йому список і компаратор. Він використовує модифікований алгоритм злиття над списком. Ось чому ви повинні пройти його компаратор, щоб зробити парне порівняння.

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 має порівнянний тип (той, який реалізує Порівняний інтерфейс) (наприклад, Дата, Цілий чи Строковий), ви можете опустити компаратор і буде використано природне впорядкування.


1
І чи повертає цей мій список, коли це зроблено чи щось подібне?

Він модифікує мій список. Тож її сортували, коли вона закінчується
— геліос


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

Найкраща відповідь IMHO з Tunaki, використовуючи лямбду Java 8


8

Враховуючи, MyObjectщо має DateTimeчлен з getDateTime()методом, ви можете сортувати елемент, ArrayListякий містить MyObjectелементи за такими DateTimeоб'єктами:

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

Що робити, якщо я хочу замовити основу на поточний системний час.
— Користувач3

5

Ось як я вирішив:

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

Сподіваюся, це допоможе вам.


як повернути його за датою?
— Зомбі

2

Завдяки впровадженню Java 1.8, потоки дуже корисні для вирішення подібних проблем:

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

Усі відповіді тут я виявив не обов'язково складними для простої проблеми (принаймні для досвідченого розробника Java, яким я не є). У мене була аналогічна проблема, і я застосував цей (та інші) рішення, і хоча вони вказували на початківця, я знайшов початківця, як сказано вище. Моє рішення, залежить від того, де в Object ваша дата, в даному випадку дата є першим елементом Object [], де dataVector - це ArrayList, що містить ваші об'єкти.

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

6
Наскільки ваша відповідь менш складна або більш правильна, ніж інші відповіді тут? На мою думку, відповідь WhiteFang32, наприклад, дуже схожа і більш коротка.
— amotzg

На деякий час віддалився, тому не побачив відгуку, але потім знову, краще пізно, ніж ніколи. Я думаю, що стислість у відповіді WhiteFang була недоліком моїх (тоді) недосвідчених очей розробника Java! Включення мовної передачі у мою відповідь було клинчером (на мою думку, принаймні, тоді). Залишилося, де ви вирвали твердження, що моя відповідь була правильнішою за інших? Я випускаю пар я гадаю .. все прощено!
— Непалуз

O.getDateTime () полягав не в наборі тексту, а в описі ОП DateTimeоб'єкта, який міститься в іншому об'єкті. Якби це було тільки Dateабо DateTimeоб'єкти, які Comparableне було ніякої необхідності для Comparatorв першу чергу.
— amotzg

Не мав на увазі сказати, що ваша відповідь менш правильна або інакше менш добра. Я просто шукав інформацію, щоб допомогти мені краще зрозуміти її. Перепрошую, якщо здавалося, що це інакше.
— amotzg

0

Це може бути старий відповідь , але я використав кілька прикладів з цього поста , щоб створити компаратор , який буде сортувати ArrayListпо HashMap<String, String>одним об'єктом в списку, що є мітка часу.

У мене є ці об'єкти:

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

Об'єкти карти такі:

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

Це відображення - це те, що я використовую для завантаження всіх моїх об'єктів у список масивів, використовуючи alList.add(map)функцію, в циклі.

Тепер я створив власний компаратор:

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

Тепер я можу просто зателефонувати на компаратор у будь-який час на масив, і він буде сортувати мій масив, даючи мені останню часову позначку в позиції 0 (вгорі списку) та найдавнішу часову позначку в кінці списку. Нові повідомлення в основному ставлять на початок.

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

Це може допомогти комусь, тому я і розмістив це. Враховуйте твердження про повернення в межах функції порівняння (). Є 3 типи результатів. Повернення 0, якщо вони рівні, повернення> 0, якщо перша дата є перед другою датою, і повернення <0, якщо перша дата є після другої дати. Якщо ви хочете, щоб ваш список був перетворений, просто перемкніть ці два заяви про повернення! Простий =]


Я хотів додати коментар до цього. Звичайно, є "NullPointerExceptions" при обробці списку масивів (з огляду на оператор return 0). Тому вам доведеться поводитися з ними, оскільки кожен випадок буде різним. Наприклад, список з 0 об'єктами створить NullPointerException або список з 1 об'єктом!
— Брендон

0

Передайте аргумент 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

Використовуйте підхід нижче, щоб визначити дати впорядковані чи ні

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
Схоже, це не відповідає на питання. І, будь ласка, не вчіть молодих людей користуватися давно застарілим та сумно відомим клопотом SimpleDateFormat. Принаймні, не як перший варіант. І не без жодного застереження. Сьогодні ми набагато краще java.timeвживаємо сучасний API дати та часу Java та його DateTimeFormatter.
— Оле ВВ

0

Клас Дата вже реалізує інтерфейс компаратора. Припустимо, що у вас є клас нижче:

public class A {

    private Date dateTime;

    public Date getDateTime() {
        return dateTime;
    }

    .... other variables

}

Скажімо, у вас є список об'єктів A як List<A> aList, ви можете легко сортувати його за допомогою потокового API Java 8 (фрагмент нижче):

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

...

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

-1

Майбутні глядачі, я думаю, що це найпростіше рішення, якщо ваша модель містить дату рядка типу (наприклад, "2020-01-01 10:00:00"), тоді просто напишіть наступний рядок для сортування даних за датою, що починається від новітні до найстаріших:

Collections.sort(messages, (o1, o2) -> o2.getMessageDate().compareTo(o1.getMessageDate()));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.