'How to Sum up all BigDecimal in list of Objects

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



Solution 1:[1]

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1