Java中数组列表比较日期后返回最近的日期

ie3xauqp  于 2023-10-14  发布在  Java
关注(0)|答案(5)|浏览(101)

如何在比较数组列表中的所有元素后返回最近的日期?期望返回2023-01-03T02:00:00.800Z值,因为它是列表中所有元素中最近的日期。有人能帮帮忙吗?
我使用JDoodle创建了一个工作示例

验证码

import java.util.ArrayList;

class Car {
  String name;
  String sold;
  Car(String name, String sold) {
    this.name = name;
    this.sold = sold;
  }
}
public class MyClass {
  public static void main(String args[]) {
    ArrayList <Car> carsList = new ArrayList <Car> ();

    carsList.add(new Car("BMW", "2023-01-01T02:00:00.800Z"));
    carsList.add(new Car("Jeep", "2023-01-02T02:00:00.800Z"));
    carsList.add(new Car("Benz", "2023-01-03T02:00:00.800Z"));

    for (int i = 0; i < carsList.size(); i++) {
      for (int j = i + 1; j < carsList.size(); j++) {
        int res = carsList.get(i).sold.compareTo(carsList.get(j).sold);
        System.out.println(res);
      }
    }
  }
}
9jyewag0

9jyewag01#

我建议您将sold声明为Instant。但是,如果出于某种原因想将其保留为String,则可以将其解析为Instant。请注意,您的日期-时间字符串已经是ISO 8601;因此,您不需要使用DateTimeFormatter来解析它们。

carsList.stream()
        .max(Comparator.comparing(car -> Instant.parse(car.sold)))
        .get()
        .sold

Online Demo
从**Trail: Date Time**了解有关现代日期-时间API的更多信息

y3bcpkx1

y3bcpkx12#

其他答案都是正确的。但这里有一些替代语法,并使用正确的日期时间类型。我们看到了Java 21+中的新SequencedCollection功能。

tl;dr

将类定义为实现Comparable的记录。

record CarSale( String name , Instant whenSold ) implements Comparable < CarSale >
{
    private static final Comparator < CarSale > COMPARATOR =
            Comparator
                    .comparing ( CarSale :: whenSold )
                    .thenComparing ( CarSale :: name );

    @Override
    public int compareTo ( final CarSale other )
    {
        return CarSale.COMPARATOR.compare ( this , other );
    }
}

将得到的排序集合定义为SequencedCollection,其实现为TreeSet。获取最新的汽车销售通过获取收集的最后一个元素。

CarSale latest =
        new TreeSet <> (
                List
                        .of (
                                new CarSale ( "BMW" , Instant.parse ( "2023-01-01T02:00:00.800Z" ) ) ,
                                new CarSale ( "Benz" , Instant.parse ( "2023-01-03T02:00:00.800Z" ) ) ,
                                new CarSale ( "Jeep" , Instant.parse ( "2023-01-02T02:00:00.800Z" ) )
                        )
        )
                .getLast ( );  // Java 21+.

CarSale[name=Benz,whenSold=2023-01-03T02:00:00.800Z]

详情

安装

你们的名字有点模糊。sold可以更清晰,如whenSold。而Car级实际上是关于一辆车何时售出的。所以CarSale更精确。

记录

如果Car类的主要目的是透明地传递浅不可变数据,则将类定义为record。编译器隐式创建构造函数、getter、equals & hashCodetoString

record CarSale ( String name , String whenSold ) {}

java.time.Instant

第二个参数whenSold代表一个时刻,时间轴上的一个点。Java包含了 java.time 类来处理这样的日期-时间工作。使用java.time.Instant表示时间轴上的一个点,以UTC表示(与UTC的偏移量为零小时-分钟-秒)。

record CarSale ( String name , Instant whenSold ) {}

您的输入字符串使用标准ISO 8601格式来表示该时刻。java.time 类在解析/生成文本时默认使用ISO 8601格式。所以我们可以直接解析你的输入。

CarSale car = new CarSale ( "BMW" , Instant.parse( "2023-01-01T02:00:00.800Z" ) ) ;

List.of

您可以使用List. of更紧凑地收集示例化的CarSale对象。这将生成一个不可修改的List对象。
您的示例数据已按所需的排序顺序排列。所以我改变了你的原始订单,这样我们就可以验证分类正在进行。

List < CarSale > carSales =
        List.of (
                new CarSale ( "BMW" , Instant.parse ( "2023-01-01T02:00:00.800Z" ) ) ,
                new CarSale ( "Benz" , Instant.parse ( "2023-01-03T02:00:00.800Z" ) ),
                new CarSale ( "Jeep" , Instant.parse ( "2023-01-02T02:00:00.800Z" ) ) 
        );

Comparable

其他答案适用于Comparator。这是一个有效的办法。但是,如果您对这些CarSale记录进行排序的主要默认方式是whenSold,那么将其作为特性构建到您的类中。要实现这一点,请使用compareTo方法实现Comparable接口。
为了实现compareTo,我们可以定义一个包含的Comparator来完成这项工作。使static具有singletonconstant
当在whenSold上排序时,当同时出售两辆或更多汽车时,我们可能会有平局。为了打破僵局,我们可以看看唯一的另一个属性name

private static final Comparator < CarSale > COMPARATOR =
        Comparator
                .comparing ( CarSale :: whenSold )
                .thenComparing ( CarSale :: name );

完成compareTo方法。

@Override
public int compareTo ( final CarSale other )
{
    return CarSale.COMPARATOR.compare ( this , other );
}

排序

最后,我们进入排序。
我们有一个不可修改的列表,无法排序。因此,我们需要创建一个可修改的集合,可以排序。我们可以通过将不可修改的列表传递给可修改的List实现的构造函数来做到这一点。

new ArrayList <> ( carSales )

Stream排序

从那里,我们可以通过创建一个流来进行排序,要求流使用我们的CarSale对象的“自然顺序”进行排序。自然顺序是由Comparable决定的顺序。我们将得到的排序元素收集到另一个List中。

List < CarSale > carSalesSorted = new ArrayList <> ( carSales ).stream ( ).sorted ( ).toList ( );

SequencedCollection

在Java 21中,我们可以使用更通用的接口SequencedCollection而不是List。请参见JEP 431: Sequenced Collections

SequencedCollection < CarSale > carSalesSorted = new ArrayList <> ( carSales ).stream ( ).sorted ( ).toList ( );

TreeSet代替ArrayList

此时,我们意识到可以使用SequencedCollection的不同实现。我们可以使用TreeSet,它会自动将其元素按排序顺序保存。只有当我们不关心跟踪重复对象时,这才有效,因为TreeSetSet实现禁止重复。我们可以简单地将不可修改的List传递给TreeSet的构造函数。

SequencedCollection < CarSale > carSalesSorted = new TreeSet <> ( carSales );

要访问这些元素,请执行以下操作:例如,调用java.lang.Iterable#forEach。这是因为每个SequencedCollection对象也是一个Iterable对象。

carSalesSorted.forEach ( System.out::println );

运行时:

CarSale[name=BMW, whenSold=2023-01-01T02:00:00.800Z]
CarSale[name=Jeep, whenSold=2023-01-02T02:00:00.800Z]
CarSale[name=Benz, whenSold=2023-01-03T02:00:00.800Z]

getLast

通过从SequencedCollection中获取最后一个元素来确定最新的汽车销售。只需调用getLast

CarSale latest = carSalesSorted.getLast ( );

CarSale[name=Benz,whenSold=2023-01-03T02:00:00.800Z]
完整的代码示例:

package work.basil.example;

import java.time.Instant;
import java.util.*;

public class CarsLedger
{
    public static void main ( String[] args )
    {
        record CarSale( String name ,
                        Instant whenSold ) implements Comparable < CarSale >
        {
            private static final Comparator < CarSale > COMPARATOR =
                    Comparator
                            .comparing ( CarSale :: whenSold )
                            .thenComparing ( CarSale :: name );

            @Override
            public int compareTo ( final CarSale other )
            {
                return CarSale.COMPARATOR.compare ( this , other );
            }
        }
        List < CarSale > carSales =
                List.of (
                        new CarSale ( "BMW" , Instant.parse ( "2023-01-01T02:00:00.800Z" ) ) ,
                        new CarSale ( "Benz" , Instant.parse ( "2023-01-03T02:00:00.800Z" ) ) ,
                        new CarSale ( "Jeep" , Instant.parse ( "2023-01-02T02:00:00.800Z" ) )
                );

        //SequencedCollection < CarSale > carSalesSorted = new ArrayList <> ( carSales ).stream ( ).sorted ( ).toList ( );

        SequencedCollection < CarSale > carSalesSorted = new TreeSet <> (
                List.of (
                        new CarSale ( "BMW" , Instant.parse ( "2023-01-01T02:00:00.800Z" ) ) ,
                        new CarSale ( "Benz" , Instant.parse ( "2023-01-03T02:00:00.800Z" ) ) ,
                        new CarSale ( "Jeep" , Instant.parse ( "2023-01-02T02:00:00.800Z" ) )
                )
        );

        carSalesSorted.forEach ( System.out :: println );

        CarSale latest = carSalesSorted.getLast ( );
        System.out.println ( "latest = " + latest );
    }
}
wa7juj8i

wa7juj8i3#

您可以将for循环替换为:

String mostRecentDate = carsList.get(0).sold;

for (int i = 1; i < carsList.size(); i++) {
  String currentDate = carsList.get(i).sold;
  if (currentDate.compareTo(mostRecentDate) > 0) {
    mostRecentDate = currentDate;
  }
}

但说实话,最好的方法是将sold作为LocalDateTime(因为它是一个日期),并使用以下命令比较日期:

if (currentDate.isAfter(mostRecentDate)) {
    mostRecentDate = currentDate;
}
9wbgstp7

9wbgstp74#

  • "...在比较数组列表中的所有元素后,如何返回最近的日期?..."*

您可以使用 ZonedDateTime#parse 方法。
比较 Ba,首先按最近的日期排序。

import static java.time.ZonedDateTime.parse;
carsList.sort((a, b) -> parse(b.sold).compareTo(parse(a.sold)));

或者,在一条线上,用一条 * 流 *。

Car c = carsList.stream()
                .sorted((a, b) -> parse(b.sold).compareTo(parse(a.sold)))
                .findFirst()
                .get();

输出

Benz 2023-01-03T02:00:00.800Z

如果你不想使用流或闭包,你可以使用 anonymous-class

carsList.sort(new Comparator<>() {
    @Override
    public int compare(Car a, Car b) {
        return parse(b.sold).compareTo(parse(a.sold));
    }
});
f0ofjuux

f0ofjuux5#

您可以流式传输汽车,提取日期并找到最大日期,如下所示:

String maxDate = carsList.stream()
    .map(car -> car.sold)
    .max(String::compareTo)
    .orElse(null); // return null if no "sold" timestamps found

请参见live demo
你的日期(实际上是时间戳)只有作为字符串才有意义,因为它们是ISO格式的。使用更合适的类型来存储它们会更好、更清晰,比如LocalDateTime

相关问题