【问题标题】:Sort list by LocalDate descending and LocalTime ascending按 LocalDate 降序和 LocalTime 升序对列表进行排序
【发布时间】:2020-10-05 03:06:13
【问题描述】:

我有一个包含LocalDateTime 字段的对象列表。
我想根据日期和时间对所有这些对象进行非常特别的排序。

我解释一下应该怎么做:

按日期降序排序BUT按时间升序

这是一个例子:

未排序LocalDateTime:

  • 2016-10-06T09:10
  • 2016-10-06T10:34
  • 2016-12-06T11:15
  • 2016-11-06T10:34
  • 2016-12-06T10:10
  • 2016-12-06T06:56

应该按这个顺序排序:

  1. 2016-12-06T06:56
  2. 2016-12-06T10:10
  3. 2016-12-06T11:15
  4. 2016-11-06T10:34
  5. 2016-10-06T09:10
  6. 2016-10-06T10:34

请记住,我需要对带有字段的对象进行排序,而不是 LocalDateTime 的列表,而是带有 LocalDateTime 字段的对象列表。

谢谢你帮助我:)

【问题讨论】:

  • 为此写一个自定义Coparator...
  • 我真的很想提供一个解决方案,但你没有表现出任何努力,只是要求......你能添加任何你试图解决这个问题的东西吗?问题的最后一句话中有一个 I(Remember that I need to sort ...)指向您...
  • @OleV.V.我使用传统语法写了一个答案来解决这个问题。我也尝试使用您的 lambda 语法方法,但无法使其正常工作。也许您愿意自己尝试一个工作示例。我很想看看它的实际效果。
  • 请注意出现在此网页上的以下内容:How do I ask and answer homework questions? (1) 首先真诚地尝试自己解决问题。 (2) 询问您现有实施的具体问题。
  • @OleV.V.好吧,我设法使您的代码变体正常工作。有没有更短或更好的方法?

标签: java list sorting date comparator


【解决方案1】:

LocalDateTime 对象知道如何按时间顺序对自己进行排序。您希望按日期降序排序(倒序,较晚的日期在前)但也按时间升序排序(按时间顺序)意味着该类实现 compareTo 方法的内置功能(由Comparable interface) 无法完成这项工作。

常规语法

对于自定义排序,编写您自己的Comparator 实现。该接口需要实现一种方法:compare。

这里的逻辑很简单:

  • 比较日期部分。
    • 如果两个日期不同,请在此基础上反向排序,然后在列表中向下移动。
    • 如果两者的日期相同,则深入挖掘以比较它们的时间部分,并按时间顺序排序。

代码。

package work.basil.example;

import java.time.LocalDateTime;
import java.util.Comparator;

public class LocalDateTimeComparator implements Comparator < LocalDateTime >
{
    @Override
    public int compare ( LocalDateTime o1 , LocalDateTime o2 )
    {
        // Compare the date portion first. If equal, then look at time-of-day.
        int result = o1.toLocalDate().compareTo( o2.toLocalDate() ); // Consider only the date portion first.
        result = ( ( - 1 ) * result ); // Flip the positive/negative sign of the int, to get ascending order. Or more simply: `= - result ;`.
        if ( 0 == result ) // If dates are equal, look at the time-of-day.
        {
            System.out.println( "reversing " );
            result = o1.toLocalTime().compareTo( o2.toLocalTime() );
        }
        return result;
    }
}

用这个比较器试试你的示例数据。

List < LocalDateTime > ldts = List.of(
        LocalDateTime.parse( "2016-10-06T09:10" ) ,
        LocalDateTime.parse( "2016-10-06T10:34" ) ,
        LocalDateTime.parse( "2016-12-06T11:15" ) ,
        LocalDateTime.parse( "2016-11-06T10:34" ) ,
        LocalDateTime.parse( "2016-12-06T10:10" ) ,
        LocalDateTime.parse( "2016-12-06T06:56" )
);

List < LocalDateTime > sorted = new ArrayList <>( ldts );
Comparator < LocalDateTime > comparator = new LocalDateTimeComparator();
sorted.sort(  comparator );

转储到控制台。我们看到了成功。日期按 2016 年 10 月、11 月和 12 月的日期顺序排列,而时间则按日期排列

System.out.println( "ldts = " + ldts );
System.out.println( "sorted = " + sorted );

ldts = [2016-10-06T09:10, 2016-10-06T10:34, 2016-12-06T11:15, 2016-11-06T10:34, 2016-12-06T10:10, 2016-12- 06T06:56]

排序 = [2016-12-06T06:56, 2016-12-06T10:10, 2016-12-06T11:15, 2016-11-06T10:34, 2016-10-06T09:10, 2016-10- 06T10:34]

Lambda 语法

comment by Ole V.V. 展示了如何在现代 Java 中使用函数式 lambda 语法进行等效工作。该评论启发我尝试函数式方法。

这里的想法是使用两个Comparator 对象:一个用于日期,一个用于时间。我们可以通过调用Comparator::thenComparing 将一个Comparator 嵌套在另一个中。所以我们需要建立两个比较器,然后将一个提供给另一个。我们实例化一个comparatorDate,然后给它一个comparatorTime,得到一个comparatorDateThenTime。我们将comparatorDateThenTime 传递给sort 方法以实际执行排序工作。

List < LocalDateTime > ldts = List.of(
        LocalDateTime.parse( "2016-10-06T09:10" ) ,
        LocalDateTime.parse( "2016-10-06T10:34" ) ,
        LocalDateTime.parse( "2016-12-06T11:15" ) ,
        LocalDateTime.parse( "2016-11-06T10:34" ) ,
        LocalDateTime.parse( "2016-12-06T10:10" ) ,
        LocalDateTime.parse( "2016-12-06T06:56" )
);

List < LocalDateTime > sorted = new ArrayList <>( ldts );

Comparator < LocalDateTime > comparatorDate =
        Comparator
                .comparing( ( LocalDateTime ldt ) -> ldt.toLocalDate() )
                .reversed();

Comparator < LocalDateTime > comparatorTime =
        Comparator
                .comparing( ( LocalDateTime ldt ) -> ldt.toLocalTime() );

Comparator < LocalDateTime > comparatorDateThenTime =
        comparatorDate
                .thenComparing(
                        comparatorTime
                );

sorted.sort( comparatorDateThenTime );

// Dump to console.
System.out.println( "ldts = " + ldts );
System.out.println( "sorted = " + sorted );

ldts = [2016-10-06T09:10, 2016-10-06T10:34, 2016-12-06T11:15, 2016-11-06T10:34, 2016-12-06T10:10, 2016-12- 06T06:56]

排序 = [2016-12-06T06:56, 2016-12-06T10:10, 2016-12-06T11:15, 2016-11-06T10:34, 2016-10-06T09:10, 2016-10- 06T10:34]

我们可以使用从调用Comparator.comparing 和Comparator.reversed 中返回的匿名Comparator 对象,使用单行代码将所有这些组合在一起。

List < LocalDateTime > ldts = List.of(
        LocalDateTime.parse( "2016-10-06T09:10" ) ,
        LocalDateTime.parse( "2016-10-06T10:34" ) ,
        LocalDateTime.parse( "2016-12-06T11:15" ) ,
        LocalDateTime.parse( "2016-11-06T10:34" ) ,
        LocalDateTime.parse( "2016-12-06T10:10" ) ,
        LocalDateTime.parse( "2016-12-06T06:56" )
);

List < LocalDateTime > sorted = new ArrayList <>( ldts );

sorted.sort(
        Comparator
                .comparing( ( LocalDateTime ldt ) -> ldt.toLocalDate() )
                .reversed()
                .thenComparing(
                        Comparator
                                .comparing( ( LocalDateTime ldt ) -> ldt.toLocalTime() )
                )

);

// Dump to console.
System.out.println( "ldts = " + ldts );
System.out.println( "sorted = " + sorted );

ldts = [2016-10-06T09:10, 2016-10-06T10:34, 2016-12-06T11:15, 2016-11-06T10:34, 2016-12-06T10:10, 2016-12- 06T06:56]

排序 = [2016-12-06T06:56, 2016-12-06T10:10, 2016-12-06T11:15, 2016-11-06T10:34, 2016-10-06T09:10, 2016-10- 06T10:34]

我想我更愿意在生产代码中看到第一个,即多行的。但我不确定。

问题中陈述的真正问题涉及LocalDateTime 作为另一个类的成员字段。因此,让我们扩展我们的解决方案以包含该嵌套类。在这里,我们发明了一个Happening 类,该类由一个描述字符串和一个LocalDateTime 对象组成。

package work.basil.example;

import java.time.LocalDateTime;
import java.util.Objects;

public class Happening
{
    private String description;
    private LocalDateTime localDateTime;

    public Happening ( String description , LocalDateTime localDateTime )
    {
        this.description = Objects.requireNonNull( description );
        this.localDateTime = Objects.requireNonNull( localDateTime );
    }

    public String getDescription ( ) { return this.description; }

    public LocalDateTime getLocalDateTime ( ) { return this.localDateTime; }

    @Override
    public String toString ( )
    {
        return "Happening{ " +
                "description='" + description + '\'' +
                " | localDateTime=" + localDateTime +
                " }";
    }
}

让我们收集这些对象,并使用类似于上面看到的代码进行排序。我们必须多做一步,从每个Happening 对象中提取一个LocalDateTime 对象。

List < Happening > happenings = List.of(
        new Happening( "aaa" , LocalDateTime.parse( "2016-10-06T09:10" ) ) ,
        new Happening( "bbb" , LocalDateTime.parse( "2016-10-06T10:34" ) ) ,
        new Happening( "ccc" , LocalDateTime.parse( "2016-12-06T11:15" ) ) ,
        new Happening( "ddd" , LocalDateTime.parse( "2016-11-06T10:34" ) ) ,
        new Happening( "eee" , LocalDateTime.parse( "2016-12-06T10:10" ) ) ,
        new Happening( "fff" , LocalDateTime.parse( "2016-12-06T06:56" ) )
);

List < Happening > sorted = new ArrayList <>( happenings );

sorted.sort(
        Comparator
                .comparing( ( Happening happening ) -> happening.getLocalDateTime().toLocalDate() )
                .reversed()
                .thenComparing(
                        Comparator
                                .comparing( ( Happening happening ) -> happening.getLocalDateTime().toLocalTime() )
                )

);

// Dump to console.
System.out.println( "happenings = " + happenings );
System.out.println( "sorted = " + sorted );

运行时,我们从 a-b-c-d-e-f 到 f-e-c-d-a-b 顺序。

发生 = [发生{ description='aaa' | localDateTime=2016-10-06T09:10 },发生{描述='bbb' | localDateTime=2016-10-06T10:34 },正在发生{ description='ccc' | localDateTime=2016-12-06T11:15 },发生{描述='ddd'| localDateTime=2016-11-06T10:34 },发生{描述='eee'| localDateTime=2016-12-06T10:10 },正在发生{ description='fff' | localDateTime=2016-12-06T06:56 }]

排序 = [发生{描述='fff' | localDateTime=2016-12-06T06:56 },正在发生{ description='eee' | localDateTime=2016-12-06T10:10 },正在发生{ description='ccc' | localDateTime=2016-12-06T11:15 },发生{描述='ddd'| localDateTime=2016-11-06T10:34 },发生{描述='aaa' | localDateTime=2016-10-06T09:10 },发生{描述='bbb' | localDateTime=2016-10-06T10:34 }]

【讨论】:

    猜你喜欢
    • 2016-10-18
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    • 2020-11-09
    • 2018-05-03
    • 1970-01-01
    • 2015-08-30
    相关资源
    最近更新 更多