Сортировать объекты в ArrayList по дате?


149

Каждый пример, который я нахожу, касается алфавитного подхода, в то время как мои элементы сортируются по дате.

Мой ArrayList содержит объекты, для которых одна из камер данных является объектом DateTime. На DateTime я могу вызвать функции:

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

Поэтому для сравнения я мог бы сделать что-то вроде:

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

Что я должен делать внутри блока if?


3
Я опубликовал решение, но если вы хотите получить представление о заказе, вы должны прочитать об алгоритмах заказа (пузырьковая сортировка, слияние, быстрая сортировка и т. Д.).
Гелиос

Спасибо, я посмотрю на них, я ничего не знаю о сортировке

В этой теме можно найти несколько полезных решений Java 1.8: stackoverflow.com/questions/36361156/…
lradacher

Ответы:


418

Вы можете сделать свой объект сопоставимым:

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
Две причины - простота и безотказность. Вы хотите, чтобы код был максимально простым, и если вы уверены, что ваше свойство не должно быть нулевым, вы, вероятно, захотите, чтобы ваш код потерпел неудачу как можно скорее, если вы столкнетесь с нулем, вместо этого передавая неверные данные и ломаясь еще дальше от места где были введены неверные данные.
Domchi

3
если o1 или o2 равно нулю, вернуть 0; // эта строка может вызвать ошибку, так как возвращение 0 означает, что они равны.
tanyehzheng

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

1
Вы должны проверить для каждой даты ноль отдельно и отсортировать по желанию (либо ноль сортирует в начале или в конце последовательности). То есть, если одна дата равна нулю, а другая не равна нулю, вернуть 1 или -1. Без этого нули не сортируются и остаются там, где они оказались в списке до сортировки.
droozen

64

Начиная с Java 8 интерфейс List предоставляет метод sort . В сочетании с лямбда- выражением самым простым решением будет

// 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)
whitebrow

@ Тунаки, как сделать обратную сортировку?
лилия

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 имеет сопоставимый тип (тот, который реализует интерфейс Comparable) (например, Date, Integer или String), вы можете опустить компаратор, и будет использоваться естественный порядок.


1
И это возвращает myList, когда это сделано или что-то в этом роде?

Это модифицирует мой список. Таким образом, его сортируют, когда он заканчивается
helios


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

Лучший ответ ИМХО от Тунаки с использованием 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;
    }
});

Что делать, если я хочу сделать заказ на основе текущего системного времени.
User3

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, которым я не являюсь). У меня была похожая проблема, и я случайно наткнулся на это (и другие) решения, и хотя они предоставили указатель, для новичка, которого я нашел, как указано выше. Мое решение зависит от того, где в Объекте ваша Дата находится, в данном случае, дата является первым элементом Объекта [], где 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 () речь шла не о наборе текста, а об описании OP 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;
    }
}

Теперь я могу просто вызвать Comparator в любое время в массиве, и он будет сортировать мой массив, давая мне самую последнюю временную метку в позиции 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

Класс Date уже реализует интерфейс Comparator. Предполагая, что у вас есть класс ниже:

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.