如果两个属性具有相同的值,则比较器是可选的

uqdfh47h  于 2022-09-19  发布在  Spring
关注(0)|答案(3)|浏览(167)

目前,我正在处理一个场景,其中我必须找到最小时间戳并打印相应的金额,第二个场景是假设如果两个数据的时间戳相同,那么我必须打印时间戳和金额之和。我无法通过比较器实现第二种情况。如果你们有什么解决方案或其他选择,请告诉我。
代码:

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

class Student {
    private String timestamp;
    private int amount;

    public Student(String timestamp, int amount) {
        this.timestamp = timestamp;
        this.amount = amount;
    }

    public String getTimestamp() {
        return timestamp;
    }

    public int getAmount() {
        return amount;
    }

    @Override
    public String toString() {
        return "Student{" +
                "timestamp='" + timestamp + '\'' +
                ", amount=" + amount +
                '}';
    }
}

public class Main
{
    public static void main(String[] args)
    {
        List<Student> students = Arrays.asList(
                new Student("2022-06-06 14:19:37.000", 25),
                new Student("2022-06-06 14:19:37.000", 15),
        );

        Comparator<Student> timestampComparator = Comparator
      .comparing(Student::getTimestamp);
    Student earliestDate = students.stream()
      .min(timestampComparator)
      .get();
    }
}

预计产量-2022-06-06 14:19:37.000,40
我得到的输出-2022-06-06 14:19:37.000,25

sg3maiej

sg3maiej1#

您不需要Comparator,您需要的是对结果进行分组和聚合。
因为您需要实际日期,所以应该使用java.time,即现代java日期时间API。为了简单起见,我将使用LocalDateTime并假设所有学生都在同一(默认)时区。更改学生类别:

public class Student {

  private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

  private final LocalDateTime timestamp;
  private final int amount;

  public Student(String timestamp, int amount) {
    this.timestamp = LocalDateTime.parse(timestamp, FORMATTER);
    this.amount = amount;
  }

  public LocalDateTime getTimestamp() {
    return timestamp;
  }

  public int getAmount() {
    return amount;
  }
}

注意我是如何将字符串解析为LocalDateTime的。
数据的实际分组和聚合;

public class Temp {

  public static void main(String[] args) {
    List<Student> students = Arrays.asList(new Student("2022-06-06 14:19:37.000", 25),
            new Student("2022-06-06 14:19:37.000", 15),
            new Student("2022-06-06 14:19:38.000", 15));
    Map.Entry<LocalDateTime, Integer> result = students.stream()
            .collect(Collectors.toMap(Student::getTimestamp, Student::getAmount, Integer::sum, TreeMap::new))
            .firstEntry();
    System.out.println(result.getKey() + ", " + result.getValue());
  }
}

我正在将数据收集到Map<LocalDateTime, Integer>中,键是时间戳,值是每个学生的时间戳金额总和。
1.Student::getTimestamp-通过提取学生的时间戳为Map生成密钥的函数。
1.Student::getAmount-通过提取学生的金额为键生成函数值。
1.Integer::sum-合并函数,处理键冲突(键已存在),该值被当前值+新值替换。
1.TreeMap::new-功能,提供Map,其中收集数据。我使用TreeMap,因为它是按键排序的,并且很容易提取具有最小键的键/值对。
请参阅催收员的文档。有关其他信息,请参见toMap()。

p4rjhz4m

p4rjhz4m2#

您希望首先按时间戳进行分组,并计算每个时间戳的总和(如果该时间戳只有一个项,则总和将仅为该项的值)。这不需要比较器。接下来,找到最小时间戳并返回总和(这是比较器发挥作用的地方)。

int value = students.stream()
  .collect(Collectors.groupingBy(Student::getTimestamp, Collectors.summingInt(Student::getValue)))
  .entrySet()
  .stream()
  .min(Map.Entry.compareByKey())
  .map(Map.Entry::getValue)
  .findFirst()
  .orElse(0);
mec1mxoz

mec1mxoz3#

您需要第二个周期来构建总和。

public static void main(String[] args)
{
    List<Student> students = Arrays.asList(
            new Student("2022-06-06 14:19:37.000", 25),
            new Student("2022-06-06 14:19:37.000", 15));

    Comparator<Student> timestampComparator = Comparator
            .comparing(Student::getTimestamp);
    Student earliestDate = students.stream()
            .min(timestampComparator)
            .get();
    int sum = students.stream()
            .filter(s-> earliestDate.getTimestamp().equals(s.getTimestamp()))
            .mapToInt(Student::getAmount).sum();
    Student sumStudent = new Student(earliestDate.getTimestamp(), sum);
    System.out.println(sumStudent);
}

相关问题