How to Sum up all BigDecimal in list of Objects

Viewed 66

was wondering if any of the lambda can achieve something like this with the class provided here

public class DataDto {
    private BigDecimal baseAmt;
    private BigDecimal revenueAmt;
    private BigDecimal occupiedDays;
    private String timeUnit;
}

List<DataDto> data = {from db}

Map<String, BigDecimal> map = dataDtos().stream()
                    .collect(Collectors.groupingBy(DataDto ::getTimePoint,
                            Collectors.reducing(BigDecimal.ZERO, DataDto ::getBaseAmt)));

How to grouping by getTimePoint and add all the big decimal to particular fields and return to the list.

Thanks for helping

1 Answers

I can do it with a for loop. But I have not yet been able to do it with streams.

Let’s simplify your problem by defining a record with only two member fields.

record Amount( LocalDate date , BigDecimal revenue ) { }

Make some example data. We have two BigDecimal values for each of two LocalDate keys. January 23rd has 7 and 42, while April 1 has 1.2 and 1.1.

List < Amount > amounts =
        List.of(
                new Amount( LocalDate.of( 2022 , Month.JANUARY , 23 ) , new BigDecimal( "7" ) ) ,
                new Amount( LocalDate.of( 2022 , Month.APRIL , 1 ) , new BigDecimal( "1.2" ) ) ,
                new Amount( LocalDate.of( 2022 , Month.APRIL , 1 ) , new BigDecimal( "1.1" ) ) ,
                new Amount( LocalDate.of( 2022 , Month.JANUARY , 23 ) , new BigDecimal( "42" ) )
        );

Loop those.

NavigableMap < LocalDate, BigDecimal > mapTotalByDate = new TreeMap <>();
for ( Amount amount : amounts )
{
    if ( mapTotalByDate.get( amount.date() ) == null )
    {
        mapTotalByDate.put( amount.date , amount.revenue );
    } else
    {
        mapTotalByDate.put( amount.date , mapTotalByDate.get( amount.date ).add( amount.revenue ) );
    }
}

mapTotalByDate = {2022-01-23=49, 2022-04-01=2.3}

Or change that for loop to use switch rather than cascading if, as suggested by IntelliJ. I prefer this as it seems easier to read.

for ( Amount amount : amounts )
{
    switch ( mapTotalByDate.get( amount.date() ) )
    {
        case null -> mapTotalByDate.put( amount.date , amount.revenue );
        default -> mapTotalByDate.put( amount.date , mapTotalByDate.get( amount.date ).add( amount.revenue ) );
    }
}

Eliminate one of lookup on the map.

for ( Amount amount : amounts )
{
    BigDecimal subtotal = mapTotalByDate.get( amount.date() );
    switch ( subtotal )
    {
        case null -> mapTotalByDate.put( amount.date , amount.revenue );
        default -> mapTotalByDate.put( amount.date , subtotal.add( amount.revenue ) );
    }
}
Related