kotlin-sum-sumby-sumbydouble-bigdecimal-list-map-feature-image

Kotlin sum(), sumBy(), sumByDouble() and BigDecimal in List, Map example

In this Kotlin tutorial, I will show you some examples that uses sum(), sumBy(), sumByDouble() for List, Map. We’re gonna create sum() & sumByBigDecimal() which also work for List of BigDecimal objects.

Related Posts:
Kotlin List & Mutable List tutorial with examples
Kotlin Fold Example: fold(), foldRight(), foldIndexed(), foldRightIndexed()
Kotlin groupBy(), groupingBy() example


Kotlin sum()

The examples show you how to use sum() function to:

  • sum of all items in the normal List
  • sum of specific field in List of Objects (in need of map())
  • sum of specific field of all values in a Map (in need of map())

Why we need map()?
map() will create a List of quantity first, then we invoke: List<quantity>.sum()

List

We’re gonna use sum() on List<Int> and List<Double> for example.

val nums = listOf(10, 20, 30)
println(nums.sum())
// 60

val doubles = listOf(1.05, 2.05, 3.65)
println(doubles.sum())
// 6.75

sum() function can also work with List of Byte, Short, Long, Float items.

List of Objects

Now we will calculate total quantity of all Product(name, quantity, price) objects in List using sum().

Now we create a simple data class Product like this.

package com.bezkoder.kotlin.sum

data class Product(val name: String, val quantity: Int, val price: Double) {
}

Then we initialize List<Product> and we need to use map() to get the List of quantity objects before applying sum() on the result.

package com.bezkoder.kotlin.sum

fun main(args: Array<String>) {
  val products = listOf(
    Product("A", 10, 6.90),
    Product("B", 20, 3.45),
    Product("C", 30, 1.05)
  )

  val totalQuantity: Int = products.map { it.quantity }.sum()
  println(totalQuantity)
  // 60
}

Map

For Map, we also need to get the List of quantity objects before using sum(). It can be done with map() function.

val productsMap = mapOf(
	"a" to Product("A", 10, 6.90),
	"b" to Product("B", 20, 3.45),
	"c" to Product("C", 30, 1.05)
)

val totalQuantity: Int = productsMap.map { it.value.quantity }.sum()
println(totalQuantity)
// 60

Kotlin sumBy()

The examples show you ways to use sumBy() function to:

  • sum (and change value to Int) of all items in the normal List
  • sum of specific Int field in List of Objects (no need map())
  • sum of specific Int field of all values in Map of Objects (no need map())

Why we don’t need map()?
Look at protoype of sumBy() function:

inline fun sumBy(selector: (T) -> Int): Int

You can see that sumBy() receives a selector which indicates the field to be processed.

List

import kotlin.math.roundToInt

val nums = listOf(10, 20, 30)
println(nums.sumBy { it })
// 60
println(nums.sumBy { it * 2 })
// 120

val doubles = listOf(1.05, 2.05, 3.65)
println(doubles.sumBy { it.roundToInt() })
// 7

sumBy() function can also work with List of Byte, Short, Long, Float items.

List of Objects

Our work is simple now, just use sumBy() like this: sumBy { it.quantity }.

val products = listOf(
	Product("A", 10, 6.90),
	Product("B", 20, 3.45),
	Product("C", 30, 1.05)
)

val totalQuantity: Int = products.sumBy { it.quantity }
println(totalQuantity)
// 60

Map

For Map<String, Product>, we use map() to get the List of Product objects before applying sumBy() on the result.

val productsMap = mapOf(
  "a" to Product("A", 10, 6.90),
  "b" to Product("B", 20, 3.45),
  "c" to Product("C", 30, 1.05)
)

val totalQuantity: Int = productsMap.map { it.value }.sumBy { it.quantity }
println(totalQuantity)
// 60

Kotlin sumByDouble()

sumBy() always returns integer value. To work with Double, Kotlin provides sumByDouble() that calculate sum of all values produced by selector function applied to each item in the List.

inline fun sumByDouble(selector: (T) -> Double): Double

The examples show you ways to use sumByDouble() function to:

  • sum of all Double items in the normal List
  • sum of specific Double field in List of Objects (no need map())
  • sum of specific Double field of all values in Map of Objects (no need map())

List

val doubles = listOf(1.05, 2.05, 3.65)

println(doubles.sumByDouble { it })
// 6.75

println(doubles.sumByDouble { it * 2 })
// 13.5

List of Objects

We’re gonna use sumByDouble() to get total price by calculating sum of (quantity * price) of each Product type.

val products = listOf(
  Product("A", 10, 6.90),
  Product("B", 20, 3.45),
  Product("C", 30, 1.05)
)

val totalPrice: Double = products.sumByDouble { it.quantity * it.price }
println(totalPrice)
// 169.5

Map

val productsMap = mapOf(
  "a" to Product("A", 10, 6.90),
  "b" to Product("B", 20, 3.45),
  "c" to Product("C", 30, 1.05)
)

val totalPrice: Double = productsMap.map { it.value }.sumByDouble { it.price * it.quantity }
println(totalPrice)

Kotlin sum() & sumBy() for List of BigDecimal

Assume that we have a List of BigDecimal objects like this.

import java.math.BigDecimal

val bigDecimals = listOf(
  BigDecimal(124567890.0987654321),
  BigDecimal(987654321.123456789),
  BigDecimal(1122334455.66778899)
)

If we use sum() function on the List: bigDecimals.sum(). What happens?

Compiler will show an error:
None of the following functions can be called with the arguments supplied


None of the following functions can be called with the arguments supplied: 
@JvmName public fun Iterable.sum(): Int defined in kotlin.collections
@JvmName public fun Iterable.sum(): Double defined in kotlin.collections
@JvmName public fun Iterable.sum(): Float defined in kotlin.collections
@JvmName public fun Iterable.sum(): Int defined in kotlin.collections
@JvmName public fun Iterable.sum(): Long defined in kotlin.collections
@JvmName public fun Iterable.sum(): Int defined in kotlin.collections
@JvmName @SinceKotlin @ExperimentalUnsignedTypes public fun Iterable.sum(): UInt defined in kotlin.collections
@JvmName @SinceKotlin @ExperimentalUnsignedTypes public fun Iterable.sum(): UInt defined in kotlin.collections
@JvmName @SinceKotlin @ExperimentalUnsignedTypes public fun Iterable.sum(): ULong defined in kotlin.collections

It’s because Kotlin doesn’t either provide sum() or sumByBigDecimal() for BigDecimal type. So we need to create the extension functions.

sum() BigDecimal

Let’s make our sum() extension function like the following code.

fun Iterable.sum(): BigDecimal {
  var sum: BigDecimal = BigDecimal.ZERO
  for (element in this) {
    sum += element
  }
  return sum
}

Now you can use bigDecimals.sum() freely.

val bigDecimals = listOf(
  BigDecimal(124567890.0987654321),
  BigDecimal(987654321.123456789),
  BigDecimal(1122334455.66778899)
)

println(bigDecimals.sum());
// 2234556666.890011250972747802734375

sumBy() BigDecimal

sumByBigDecimal() extension function will need a selector.

fun  Iterable.sumByBigDecimal(selector: (T) -> BigDecimal): BigDecimal {
  var sum: BigDecimal = BigDecimal.ZERO
  for (element in this) {
    sum += selector(element)
  }
  return sum
}

Let’s run and check the result:

println(bigDecimals.sumByBigDecimal { it });
// 2234556666.890011250972747802734375

If you create a Foo class with two fields: name, value.
This is how we use sum() & sumByBigDecimal() to work with List of Foo objects.

val foos = listOf(
	Foo("A", BigDecimal(124567890.0987654321)),
	Foo("B", BigDecimal(987654321.123456789)),
	Foo("C", BigDecimal(1122334455.66778899))
)

println(foos.map { it.value }.sum());
// 2234556666.890011250972747802734375

println(foos.sumByBigDecimal { it.value });
// 2234556666.890011250972747802734375

Conclusion

Today we’re learned how to use sum(), sumBy(), sumByDouble() and sumByBigDecimal() for List, List of Objects & Map.

Let me summarize all of them.

  • sum(): works for almost simple List with number types, but needs map() function to work with List of custom Objects.
  • sumBy(): always returns Int value, has selector parameter so no need of map() function.
  • sumByDouble(): like sumBy() but always returns Double value.
  • BigDecimal: Kotlin doesn’t support, need to create sum() & sumByBigDecimal() extension functions.

Further Reading

Leave a Reply

Your email address will not be published. Required fields are marked *