简体   繁体   English

按日期属性对对象列表进行排序

[英]Sorting list of objects by date property

I have an object that contains two LocalDate properties:我有一个包含两个 LocalDate 属性的对象:

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

Constructor and stuff ommitted for brevity.为简洁起见省略了构造函数和内容。 I want to sort a list of these objects by their startdate and then assign the startdate of the next object to the previous object's enddate.我想按开始日期对这些对象的列表进行排序,然后将下一个对象的开始日期分配给前一个对象的结束日期。 To clarify, I start with a list of these objects:为了澄清,我从这些对象的列表开始:

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

And after sorting it should return this:排序后它应该返回这个:

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

Each list will only contain 3 or 4 of these objects at most, but the code might have to process tens of thousands of these lists, so I'm looking for an efficient way to do this.每个列表最多只包含 3 或 4 个这些对象,但代码可能必须处理数以万计的这些列表,所以我正在寻找一种有效的方法来做到这一点。

You can use Collections.sort with a Comparator.您可以将 Collections.sort 与 Comparator 一起使用。 In Java 8 with Lambdas it looks like this:在带有 Lambda 的 Java 8 中,它看起来像这样:

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

作为对已接受答案的增强:

Collections.sort(list, Comparator.comparing(SomeObject::getStartDate));

Make use of the fact that LocalDate already implements Comparable and make your SomeObject do as well.利用LocalDate已经implements Comparable的事实并使您的SomeObject也这样做。 Additionally, give it a proper toString() method, which handles null values in order to represent your object as a String :此外,给它一个适当的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();
    }
}

By doing so, you can easily just call Collections.sort(list);通过这样做,您可以轻松地调用Collections.sort(list); and have your data sorted by startDate :并按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());
        });
    }
}

As you mentioned that you didn't really care whether it is startDate or endDate and just order all of them, maybe the following will help you:正如您提到的,您并不真正关心它是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);

EDIT: There was that endDate set on one of your samples before... as that isn't the case anymore, here an update how you can set the right date ranges.编辑:之前在您的一个样本上设置了 endDate ......因为情况不再如此,这里更新您如何设置正确的日期范围。 It's basically similar to what also Ralf Renz has used in his answer:它基本上类似于 Ralf Renz 在他的回答中使用的内容:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM