La Función sum En Kotlin

En este tutorial aprenderás a usar la función sum en Kotlin para obtener la suma de los elementos de una colección numérica, a través de ejemplos. Adicionalmente verás las variaciones sumOf(), sumBy() y sumByDouble() para usar un selector que te permita mapear colecciones para disponerlas a la sumatoria.

Función sum()

La función de extensión sum() retorna en la sumatoria de todos los elementos de un arreglo o colección de números. A continuación se muestran algunas variaciones de su sintaxis:

// sum() en Arreglos
fun IntArray.sum(): Int
fun DoubleArray.sum(): Double

// sum() en colecciones
fun Iterable<Int>.sum(): Int
fun Iterable<Double>.sum(): Double

Por ejemplo, usemos la función sum() en código Kotlin para realizar la sumatoria de:

  • Los elementos de un arreglo de números reales
  • Un rango del 1 al 10
  • Una lista de números Long generados aleatoriamente entre 20 y 100
import kotlin.random.Random

fun main() {
    val decimals = doubleArrayOf(1.1, 2.2, 4.5, -1.2)
    println("sum${decimals.contentToString()} = ${decimals.sum()}")

    val fromOneToTen = 1..10
    println("sum[$fromOneToTen] = ${fromOneToTen.sum()}")

    val randomNumbers = List(5) { Random.nextLong(20, 100) }
    println("sum$randomNumbers = ${randomNumbers.sum()}")
}

Salida:

sum[1.1, 2.2, 4.5, -1.2] = 6.6000000000000005
sum[1..10] = 55
sum[60, 33, 63, 59, 63] = 278

Función sumOf()

La función sumOf() toma como parámetro una función de selección (selector) y se la aplica a cada elemento de la colección invocadora. El resultado final es el sumatorio de todos estos resultados de conversión. Las siguientes son algunas muestras de su sintaxis

// sumOf() en arreglos con resultado Double
fun <T> Array<out T>.sumOf(selector: (T) -> Double): Double

// sumOf() en colecciones con resultado Int
fun <T> Iterable<T>.sumOf(selector: (T) -> Int): Int

// sumOf() en strings con resultado Double
public inline fun CharSequence.sumOf(
    selector: (Char) → Double
): Double

Como ves, a diferencia de sum(), la función sumOf() es genérica, por lo que la colección no tiene que ser de tipo numérico. Lo importante es usar al selector para especificar el mapeado apropiado a sumar y retornar.

Considera el modelado de los vendedores de una compañía y la cantidad de ventas realizadas en el mes.

data class Salesman(val name: String, val sales: Int)

Dada una lista de vendedores, obtener el total de ventas realizado por todos los agentes:

fun main() {
    val persons = listOf(
        Salesman("Jackson", 18),
        Salesman("Miguel", 10),
        Salesman("Milena", 16),
        Salesman("Rosa", 40)
    )
    val totalSales = persons.sumOf { it.sales }
    println("Total de ventas: $totalSales")
}

Salida:

Total de ventas: 84

En el ejemplo anterior la función sumOf() es perfecta porque nos permite pasar una función lambda que acceda a la propiedad sales para usarla como ejemplar en la suma.

Función sumBy()

La función sumBy() hace exactamente lo que sumOf(), solo que el cuerpo del selector siempre es de tipo Int, al igual que el valor de la suma retornada.

// sumBy() en arreglos de tipo T 
fun <T> Array<out T>.sumBy(selector: (T) -> Int): Int

// sumBy() en colecciones
inline fun <T> Iterable<T>.sumBy(selector: (T) -> Int): Int

// sumBy() en strings
public inline fun CharSequence.sumBy(
    selector: (Char) → Int
): Int

Por ejemplo, obtengamos la suma total de todos los códigos numéricos de los caracteres del string "Develou".

fun main() {
    val string = "Develou"
    val codesSum = string.sumBy { it.toInt() }
    println("Suma de códigos: $codesSum")
}

Salida:

Suma de códigos: 724

Ya que el selector es de tipo función (Char) -> Int, el único resultado aceptable es un entero, por lo que usamos la función toInt() para permitir la agregación de cada carácter a la suma.

Función sumByDouble()

La función sumByDouble() tiene el mismo propósito que sumBy(), solo que esta vez el cuerpo del selector y el retorno son de tipo Double en cada forma de sintaxis:

// sumByDouble() en arreglos de tipo T
fun <T> Array<out T>.sumByDouble(
    selector: (T) -> Double
): Double

// sumByDouble() en colecciones
fun <T> Iterable<T>.sumByDouble(
    selector: (T) -> Double
): Double

Supón que deseas desarrollar una sumatoria de los inversos de una lista de números enteros y deseas imprimir el resultado en su versión decimal.

fun main() {
    val integers = listOf(1, 2, 3, 4, 5)
    val multiplicativeInverseSum = integers.sumByDouble { (1.0 / it) }
    val inversesInStringForm = integers.joinToString(prefix = "[", postfix = "]") { "1/$it" }
    println("sum$inversesInStringForm = $multiplicativeInverseSum")
}

Salida:

sum[1/1, 1/2, 1/3, 1/4, 1/5] = 2.283333333333333

En el ejemplo anterior usamos a la función sumByDouble() pasando como selector a la división entre el literal 1.0 y cada entero de integers. Esta operación hace explicita la conversión a Double para satisfacer el tipo (Int) -> Double esperado.

Finamente transformamos la lista para que luzca con la representación fraccionaria de cada elemento en inversesInStringForm y así imprimir el resultado final de multiplicativeInverseSum.

¿Ha sido útil esta publicación?