Котлин: сумма BigDecimal в списке
у меня есть список, который я хочу отфильтровать, а затем вернуть карту id с суммой сумм:
val totalById = list
.filter { it.status == StatusEnum.Active }
.groupBy { it.item.id }
.mapValues { it.value.sumBy { it.amount } }
для java 8 это будет:
Collectors.groupingBy(i-> i.getItem().getId(), Collectors.mapping(Item::getAmount, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))))
есть ли способ сделать это в Котлин?
3 ответов
так же, как вы использовали Collectors.reducing
в Java, вы можете использовать fold
или reduce
функции расширения в Котлине:
val bigDecimals: List<BigDecimal> = ...
val sum = bigDecimals.fold(BigDecimal.ZERO) { acc, e -> acc + e }
// or
val sum2 = bigDecimals.fold(BigDecimal.ZERO, BigDecimal::add)
вы можете создать свой собственный sumByBigDecimal
функции расширения аналогично sumByDouble
. например:
/**
* 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
}
пример использования:
val totalById = list
.filter { it.status == StatusEnum.Active }
.groupBy { it.item.id }
.mapValues { it.value.sumByBigDecimal { it.amount } }
комбинируя подход сгиба и подход функции расширения, вы можете сделать следующее:
fun Iterable<BigDecimal>.sumByBigDecimal(): BigDecimal {
return this.fold(BigDecimal.ZERO) { acc, e -> acc + e }
}
fun <T> Iterable<T>.sumByBigDecimal(transform: (T) -> BigDecimal): BigDecimal {
return this.fold(BigDecimal.ZERO) { acc, e -> acc + transform.invoke(e) }
}
используйте их следующим образом:
listOfBigs.sumByBigDecimal()
listOfWidgets.sumByBigDecimal { it.price }