get total of ArrayList, grouped according to date using lambda functions in java 8

  • A+

I have a model class for Invoice which contains the date on which purchase was made and the price.

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

I get the list of invoice which contains all the invoices for the product sold in one month:

List<Invoice> invoiceListForMonth; 

I want to get the total sales done on each day of the month.

List<BigDecimal> dayWiseSales; 

How can I get the data in list using lambda functions with java 8?


I think you need something Like this :

List<Invoice> invoiceListForMonth = new ArrayList<>(); //add some data Map<LocalDate, BigDecimal> result =                 .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                 ); 

To understand it better You can separate your work in two steps :

Map<LocalDateTime, List<Invoice>> grouping =                 .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

Note I used LocalDate from java.time API because Date is old now and I don't suggest to use it any more.


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?

Based on your comment I can create your own method which remove the time part from the Date so you can compare only the Date part like so :

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

Then you can make a call thie method in groupingBy like so :

Map<Date, List<Invoice>> grouping =                 .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))         ); 


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: