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?
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.
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.
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-
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 } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With