Сортировка списка объектов по дате - PullRequest
0 голосов
/ 29 ноября 2018

У меня есть объект, который содержит два свойства LocalDate:

public class SomeObject {
    private LocalDate startDate;
    private LocalDate endDate;
}

Конструктор и материал, опущенный для краткости.Я хочу отсортировать список этих объектов по их начальной дате, а затем назначить начальную дату следующего объекта конечной дате предыдущего объекта.Чтобы уточнить, я начну со списка этих объектов:

SomeObject object1 = new SomeObject(LocalDate.parse("2015-01-01"), null);
SomeObject object2 = new SomeObject(LocalDate.parse("2014-01-01"), null);
SomeObject object3 = new SomeObject(LocalDate.parse("2016-01-01"), null);

List<SomeObject> list = Arrays.asList(object1, object2, object3);

И после сортировки он должен вернуть следующее:

for (SomeObject object : list) {
    System.out.println(object.startDate.toString() + " " + object.endDate.toString() );
}

2014-01-01 2015-01-01
2015-01-01 2016-01-01
2016-01-01 null

Каждый список будет содержать только 3 или 4 из этих объектов вбольшинство, но код может обрабатывать десятки тысяч этих списков, поэтому я ищу эффективный способ сделать это.

Ответы [ 3 ]

0 голосов
/ 29 ноября 2018

Воспользуйтесь тем, что LocalDate уже implements Comparable, и заставьте свой SomeObject сделать то же самое.Кроме того, присвойте ему правильный toString() метод, который обрабатывает null значения, чтобы представить ваш объект как String:

public class SomeObject implements Comparable<SomeObject> {
    private LocalDate startDate;
    private LocalDate endDate;

    public SomeObject(LocalDate startDate, LocalDate endDate) {
        this.startDate = startDate;
        this.endDate = endDate;
    }

    @Override
    public int compareTo(SomeObject anotherObject) {
        return this.startDate.compareTo(anotherObject.startDate);
    }

    @Override
    public String toString() {
        String start = startDate == null ? "null" : startDate.format(DateTimeFormatter.ISO_LOCAL_DATE);
        String end = endDate == null ? "null" : endDate.format(DateTimeFormatter.ISO_LOCAL_DATE); 
        StringBuilder sb = new StringBuilder();
        sb.append(start).append(" ").append(end);
        return sb.toString();
    }
}

Таким образом, вы можете легко просто вызвать Collections.sort(list);и ваши данные отсортированы по startDate:

public class SomeObjectSorting {

    public static void main(String[] args) {
        SomeObject object1 = new SomeObject(LocalDate.parse("2015-01-01"), null);
        SomeObject object2 = new SomeObject(LocalDate.parse("2014-01-01"), LocalDate.parse("2017-01-01"));
        SomeObject object3 = new SomeObject(LocalDate.parse("2016-01-01"), null);

        List<SomeObject> list = Arrays.asList(object1, object2, object3);

        System.out.println("———— BEFORE SORTING ————");

        list.forEach(object -> {
            System.out.println(object.toString());
        });

        Collections.sort(list);

        System.out.println("———— AFTER SORTING ————");

        list.forEach(object -> {
            System.out.println(object.toString());
        });
    }
}
0 голосов
/ 29 ноября 2018

Как вы упомянули, вам на самом деле все равно, будет ли это startDate или endDate, и просто закажите все из них, может быть, вам поможет следующее:

List<LocalDate> dates = list.stream()
        .flatMap(s -> Stream.of(s.startDate, s.endDate))
        .filter(Objects::nonNull) // maybe... if nulls are required too, then skip that part here... (but also check the sorting variant then); note that I use null now if the last date is reached (check the printing part for that)
        .distinct()
        .sorted()                 // natural order
        // alternatively: natural order + nulls last
        // .sorted(Comparator.nullsLast(Comparator.comparing(Function.identity())))
        .collect(Collectors.toList());

// printing part:
IntStream.range(0, dates.size())
        .mapToObj(i -> {
            String from = Objects.toString(dates.get(i));
            String upto = Objects.toString(i < dates.size() - 1 ? dates.get(i + 1) : null); // exchange null with the end date you are expecting
            return from + " - " + upto;
        })
        .forEach(System.out::println);

РЕДАКТИРОВАТЬ: Ранее на одном из ваших сэмплов была установлена ​​endDate ... поскольку это больше не так, вот обновление, как вы можете установить правильные диапазоны дат.Это в основном похоже на то, что Ральф Ренц использовал в своем ответе:

list.sort(Comparator.comparing(SomeObject::getStartDate));
IntStream.range(0, list.size() - 1)
         .forEach(i -> list.get(i).endDate = list.get(i + 1).startDate);
// or if you care about performance, just do the same as Ralf did:
for (int i = 0; i < (list.size() - 1); i++) {
    list.get(i).endDate = list.get(i + 1).startDate;
}
0 голосов
/ 29 ноября 2018

Вы можете использовать Collections.sort с Comparator.В Java 8 с Lambdas это выглядит так:

    Collections.sort(list, (x, y) -> x.startDate.compareTo(y.startDate));

    for (int i = 0; i < (list.size() - 1); i++) {
        list.get(i).endDate = list.get(i + 1).startDate;
    }
...