java - 使用 Java 8 中的 lambda 函数获取 ArrayList 的总数,根据日期分组

标签 java lambda java-8 java-stream

我有一个发票模型类,其中包含购买日期和价格。

Class Invoice{
    Date purchaseDate;
    BigDecimal price;
    //getters and setters
}

我得到发票 list ,其中包含一个月内销售的产品的所有发票:

List<Invoice> invoiceListForMonth;

我想获得每个月每一天的总销售额。

List<BigDecimal> dayWiseSales;

如何在 java 8 中使用 lambda 函数获取列表中的数据?

最佳答案

我想你需要这样的东西:

List<Invoice> invoiceListForMonth = new ArrayList<>();
//add some data
Map<LocalDate, BigDecimal> result =
        invoiceListForMonth.stream()
                .collect(Collectors.groupingBy(
                        Invoice::getPurchaseDate
                )).entrySet().stream()//This will return a map of Map<LocalDateTime, List<Invoice>>
                .collect(Collectors.toMap(Map.Entry::getKey, // to collect with the date
                        e -> e.getValue().stream().map(Invoice::getPrice) //and the sum of
                                .reduce(BigDecimal.ZERO, BigDecimal::add)) // prices
                );

为了更好地理解它您可以将您的工作分为两步:

Map<LocalDateTime, List<Invoice>> grouping =
        invoiceListForMonth.stream()
                .collect(Collectors.groupingBy(Invoice::getPurchaseDate));

Map<LocalDate, BigDecimal> result = grouping.entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getKey,
                e -> e.getValue().stream().map(Invoice::getPrice)
                        .reduce(BigDecimal.ZERO, BigDecimal::add))
        );

Concrete example demo


请注意,我使用了 java.time API 中的 LocalDate,因为 Date 现在已经过时了,我不建议再使用它。


编辑

actually the Invoice class is used in multiple other places so I cannot change it to LocalDate. I tried to implement it using Date but my collection is grouped with date and time. I want to group using date only. Can you suggest something?

根据您的评论,您可以创建自己的方法,从日期中删除时间部分,这样您就可以像这样只比较日期部分:

public static Date getDateWithoutTime(Date date) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);

    return calendar.getTime();
}

然后你可以像这样调用 groupingBy 中的方法:

Map<Date, List<Invoice>> grouping =
        invoiceListForMonth.stream()
                .collect(Collectors.groupingBy(
                        p -> getDateWithoutTime(p.getPurchaseDate())
                ));
Map<Date, BigDecimal> result = grouping.entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getKey,
                e -> e.getValue().stream().map(Invoice::getPrice)
                        .reduce(BigDecimal.ZERO, BigDecimal::add))
        );

注意:我强烈不建议使用这个旧的 API,相反你可以移动到 java.time 这将对你有很大帮助。

关于java - 使用 Java 8 中的 lambda 函数获取 ArrayList 的总数,根据日期分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52065227/

相关文章:

java - gxt,gwt,Java。没有信息气泡的文本字段验证

ruby - 如何更改 lambda 的上下文?

java - 来自 HashSet 的并行流不会并行运行

mysql - 选择包含用户信息和媒体的帖子

java - 如何解析 Guava 对 Selenium 的影响?

java - String.format 不完全工作?

java - 使用 java 8 Streams 从 DTO 中的数组列表中删除元素

java - 将依赖项注入(inject) Guice 模块

java - 最适合存储日期和时间的 SQL 和 Java 数据类型

java - 仅当其他字段为 false 时才验证字段