Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin: Sum of BigDecimal in a list

Tags:

kotlin

I have a list that I want to filter, then return a map of id with sum of amounts:

val totalById = list
                    .filter { it.status == StatusEnum.Active }
                    .groupBy { it.item.id }
                    .mapValues { it.value.sumBy { it.amount } }

"it.amount" is BigDecimal, but looks like sumBy is Int only.

For java 8 it'd be:

Collectors.groupingBy(i-> i.getItem().getId(), Collectors.mapping(Item::getAmount, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))))

Is there a way to do it in Kotlin?

like image 260
klc Avatar asked Sep 30 '16 14:09

klc


People also ask

How do you sum a list in Kotlin?

A simple solution to calculate the sum of all elements in a List is calling the sum() function. It is available for a list of all numeric data types. i.e, Int , Long , Float , Double , Byte , Short . Note that as of Kotlin 1.5, sumBy() function is deprecated.

How do you sum BigDecimal values?

math. BigDecimal. add(BigDecimal val) is used to calculate the Arithmetic sum of two BigDecimals. This method is used to find arithmetic addition of large numbers of range much greater than the range of largest data type double of Java without compromising with the precision of the result.


2 Answers

Just like you've used Collectors.reducing in java, you can use fold or reduce extension functions in Kotlin:

val bigDecimals: List<BigDecimal> = ...
val sum = bigDecimals.fold(BigDecimal.ZERO) { acc, e -> acc + e }
// or
val sum2 = bigDecimals.fold(BigDecimal.ZERO, BigDecimal::add)

The full example on play.kotlinlang.org: https://pl.kotl.in/o6pRhrqys

Starting with Kotlin 1.4 there's now a function sumOf, that takes a selector function and sums all values returned by this selector, so you can use it as following:

val totalById = list
                .groupBy { it.id }
                .mapValues { it.value.sumOf { it.amount } }

The full example on play.kotlinlang.org: https://pl.kotl.in/jXAfoyff-

like image 75
Ilya Avatar answered Sep 19 '22 06:09

Ilya


You can create your own sumByBigDecimal extension function similar to sumByDouble. e.g.:

/**
 * Returns the sum of all values produced by [selector] function applied to each element in
 * the collection.
 */
inline fun <T> Iterable<T>.sumByBigDecimal(selector: (T) -> BigDecimal): BigDecimal {
    var sum: BigDecimal = BigDecimal.ZERO
    for (element in this) {
        sum += selector(element)
    }
    return sum
}

Example usage:

val totalById = list
        .filter { it.status == StatusEnum.Active }
        .groupBy { it.item.id }
        .mapValues { it.value.sumByBigDecimal { it.amount } }
like image 37
mfulton26 Avatar answered Sep 20 '22 06:09

mfulton26