42 - Funciones: número variable de parámetros

En el lenguaje Kotlin un método de una clase o función puede recibir una cantidad variable de parámetros utilizando la palabra clave "vararg" previa al nombre del parámetro.

Desde donde llamamos a la función pasamos una lista de valores y lo recibe un único parámetro agrupando dichos datos en un arreglo.

fun imprimir(vararg nombres: String) {
    for(elemento in nombres)
        print("$elemento ")
    println()
}

fun main(args: Array<String>) {
    imprimir("Juan", "Ana", "Luis")
}

Como podemos observar utilizamos vararg previo al nombre del parámetro y el tipo de dato que almacenará el arreglo:

fun imprimir(vararg nombres: String) {
    for(elemento in nombres)
        print("$elemento ")
    println()
}

Dentro de la función tratamos al parámetro nombres como un arreglo.

Cuando llamamos a la función imprimir no enviamos un arreglo sino una lista de String, el compilador se encarga de transformar esa lista a un arreglo.

Problema 1

Elaborar una función que reciba una cantidad variable de enteros y nos retorne su suma.

Proyecto170 - Principal.kt

fun sumar(vararg numeros: Int): Int {
    var suma = 0
    for(elemento in numeros)
        suma += elemento
    return suma
}

fun main(args: Array<String>) {
    val total = sumar(10, 20, 30, 40, 50)
    println(total)
}

La función sumar recibe un parámetro con un número variable de elementos, dentro del algoritmo recorremos el arreglo, sumamos sus elementos y retornamos la suma:

fun sumar(vararg numeros: Int): Int {
    var suma = 0
    for(elemento in numeros)
        suma += elemento
    return suma
}

Desde la main llamamos a sumar pasando en este caso 5 enteros:

    val total = sumar(10, 20, 30, 40, 50)

Recordemos que Kotlin tiene como principio permitir implementar algoritmos muy concisos, la función sumar podemos codificarla en forma más concisa con la sintaxis:

fun sumar(vararg numeros: Int) = numeros.sum()

Utilizamos una función con expresión única que calcula la suma del arreglo llamando al método sum del arreglo.

En el entorno de programación IntelliJ IDEA se presionamos la tecla "Control", disponemos la flecha del mouse sobre un método:

navegar funciones y métodos con el IntelliJ IDEA

Luego de presionar el botón del mouse se abrirá otra pestaña donde está implementado el método sum:

navegar funciones y métodos con el IntelliJ IDEA

Esto nos permite desplazarnos en nuestro programa en forma muy rápida y poder analizar algoritmos que están definidos en la librería estándar de Kotlin.

Solo un parámetro de una función puede ser de tipo vararg y normalmente es el último.

Problema 2

Elaborar una función que reciba como primer parámetro que tipo de operación queremos hacer con los siguientes datos enteros que le enviamos.

Proyecto171 - Principal.kt

enum class Operacion{
    SUMA,
    PROMEDIO
}

fun operar(tipoOperacion: Operacion, vararg arreglo: Int): Int {
    when (tipoOperacion) {
        Operacion.SUMA -> return arreglo.sum()
        Operacion.PROMEDIO -> return arreglo.average().toInt()
    }
}

fun main(args: Array<String>) {
    val resultado1 = operar(Operacion.SUMA, 10, 20, 30)
    println("La suma es $resultado1")
    val resultado2 = operar(Operacion.PROMEDIO, 10, 20, 30)
    println("El promedio es $resultado2")
}

Declaramos un enum class con dos valores posibles:

enum class Operacion{
    SUMA,
    PROMEDIO
}

A la función operar le enviamos como primer parámetro un tipo de dato Operacion y como segundo parámetro serán la lista de enteros a procesar:

fun operar(tipoOperacion: Operacion, vararg arreglo: Int): Int {
    when (tipoOperacion) {
        Operacion.SUMA -> return arreglo.sum()
        Operacion.PROMEDIO -> return arreglo.average().toInt()
    }
}

Cuando llamamos desde la main a la función operar debemos pasar como primer dato el tipo de operación que queremos hacer con la lista de enteros a enviarle:

fun main(args: Array<String>) {
    val resultado1 = operar(Operacion.SUMA, 10, 20, 30)
    println("La suma es $resultado1")
    val resultado2 = operar(Operacion.PROMEDIO, 10, 20, 30)
    println("El promedio es $resultado2")
}

La conveniencia de que el parámetro vararg sea el último es que si no respetamos esto estaremos obligado a utilizar la llamada a la función con argumentos nombrados. El programa anterior disponiendo primero el vararg será:

enum class Operacion{
    SUMA,
    PROMEDIO
}

fun operar(vararg arreglo: Int, tipoOperacion: Operacion): Int {
    when (tipoOperacion) {
        Operacion.SUMA -> return arreglo.sum()
        Operacion.PROMEDIO -> return arreglo.average().toInt()
    }
}

fun main(args: Array<String>) {
    val resultado1 = operar( 10, 20, 30, tipoOperacion = Operacion.SUMA)
    println("La suma es $resultado1")
    val resultado2 = operar(10, 20, 30, tipoOperacion = Operacion.PROMEDIO)
    println("El promedio es $resultado2")
}

Debemos en forma obligatoria nombrar el segundo parámetro en la llamada:

    val resultado1 = operar( 10, 20, 30, tipoOperacion = Operacion.SUMA)

Operador spread

Si una función recibe un parámetro de tipo vararg y desde donde la llamamos queremos enviarle un arreglo debemos indicarle al compilador tal situación, Con el primer ejemplo que vimos el código quedaría:

fun imprimir(vararg nombres: String) {
    for(elemento in nombres)
        print("$elemento ")
    println()
}

fun main(args: Array<String>) {
    val personas = arrayOf("Juan", "Ana", "Luis")
    imprimir(*personas)
}

Es decir le antecedemos el caracter * previo al arreglo que le enviamos a la función.

Problema propuesto

  • Confeccionar una función que reciba una serie de edades y nos retorne la cantidad que son mayores o iguales a 18 (como mínimo se envía un entero a la función)
Solución
Proyecto172

fun cantidadMayores(vararg edades: Int) = edades.count {it >= 18}

fun main(args: Array<String>) = println(cantidadMayores(3, 65, 32, 23, 2, 98, 23, 45, 15))