Tracks
/
Go
Go
/
Ejercicios
/
Trucos con cartas
Trucos con cartas

Trucos con cartas

Ejercicio de aprendizaje

Introducción

Slices

Los slices en Go son similares a los arrays de otros lenguajes. Guardan varios elementos de un tipo específico (o de una interfaz).

Los slices en Go se basan en arrays. Los arrays tienen un tamaño fijo. Un slice, en cambio, es una vista flexible y de tamaño dinámico de los elementos de un array.

Un slice se escribe como []T, donde T es el tipo de los elementos del slice:

var empty []int                 // an empty slice
withData := []int{0,1,2,3,4,5}  // a slice pre-filled with some data

Puedes obtener o asignar un elemento en un índice determinado que empieza en cero usando la notación de corchetes:

withData[1] = 5
x := withData[1] // x is now 5

Puedes crear un slice nuevo a partir de un slice existente tomando un rango de elementos. De nuevo con la notación de corchetes, pero especificando tanto un índice inicial (inclusive) como uno final (exclusive). Si no especificas un índice inicial, su valor predeterminado es 0. Si no especificas un índice final, su valor predeterminado es la longitud del slice.

newSlice := withData[2:4]
// => []int{2,3}
newSlice := withData[:2]
// => []int{0,1}
newSlice := withData[2:]
// => []int{2,3,4,5}
newSlice := withData[:]
// => []int{0,1,2,3,4,5}

Puedes agregar elementos a un slice con la función append. A continuación agregamos 4 y 2 al slice a.

a := []int{1, 3}
a = append(a, 4, 2)
// => []int{1,3,4,2}

append siempre devuelve un slice nuevo, y cuando solo queremos agregar elementos a un slice existente, es común reasignarlo a la variable del slice que pasamos como primer argumento, como hicimos arriba.

append también se puede usar para fusionar dos slices:

nextSlice := []int{100,101,102}
newSlice  := append(withData, nextSlice...)
// => []int{0,1,2,3,4,5,100,101,102}

Funciones variádicas

Por lo general, las funciones en Go solo aceptan una cantidad fija de argumentos. Sin embargo, también es posible escribir funciones variádicas en Go.

Una función variádica es una función que acepta una cantidad variable de argumentos.

Si el tipo del último parámetro en la definición de una función lleva el prefijo de puntos suspensivos ..., entonces la función puede aceptar cualquier cantidad de argumentos para ese parámetro.

func find(a int, b ...int) {
    // ...
}

En la función anterior, el parámetro b es variádico y podemos pasarle 0 o más argumentos a b.

find(5, 6)
find(5, 6, 7)
find(5)
Caution

El parámetro variádico debe ser el último parámetro de la función.

Las funciones variádicas funcionan convirtiendo la cantidad variable de argumentos en un slice del tipo del parámetro variádico.

Aquí tienes un ejemplo de la implementación de una función variádica.

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)

    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            return
        }
    }

    fmt.Println(num, "not found in ", nums)
}

func main() {
    find(89, 90, 91, 95)
    // =>
    // type of nums is []int
    // 89 not found in  [90 91 95]

    find(45, 56, 67, 45, 90, 109)
    // =>
    // type of nums is []int
    // 45 found at index 2 in [56 67 45 90 109]

    find(87)
    // =>
    // type of nums is []int
    // 87 not found in  []
}

En la línea find(89, 90, 91, 95) del programa anterior, los argumentos variables de la función find son 90, 91 y 95. La función find espera un parámetro int variádico después de num. Por lo tanto, el compilador convertirá estos tres argumentos en un slice de tipo int, []int{90, 91, 95}, y luego lo pasará a la función find como nums.

A veces ya tienes un slice y quieres pasarlo a una función variádica. Puedes lograrlo pasando el slice seguido de .... Eso le indica al compilador que use el slice tal cual dentro de la función variádica. En este caso, simplemente se omite el paso descrito arriba en el que se crea un slice.

list := []int{1, 2, 3}
find(1, list...) // "find" defined as shown above

Instrucciones

Como aspirante a maga, Elyse necesita practicar algunas cosas básicas. Tiene una pila de cartas que quiere manipular.

Para que sea un poco más fácil, solo usa las cartas del 1 al 10.

1. Crea un slice con ciertas cartas

Cuando practica con sus cartas, a Elyse le gusta empezar con sus tres cartas favoritas del mazo: la 2, la 6 y la 9. Escribe una función FavoriteCards que devuelva un slice con esas cartas en ese orden.

cards := FavoriteCards()
fmt.Println(cards)
// Output: [2 6 9]

2. Obtén una carta de una pila

Devuelve la carta que está en la posición index de la pila dada.

card := GetItem([]int{1, 2, 4, 1}, 2) // card == 4

Si el índice está fuera de los límites (es decir, si es negativo o está después del final de la pila), queremos devolver -1:

card := GetItem([]int{1, 2, 4, 1}, 10) // card == -1
Note

Por convención en Go, se devuelve un error en lugar de devolver un valor «fuera de los límites». Aquí el valor «fuera de los límites» es -1 cuando se espera un entero positivo. Cuando se devuelve un error, se considera idiomático devolver el zero value junto con el error. Devolver un error con el valor de retorno adecuado se cubrirá en un ejercicio futuro.

3. Intercambia una carta en la pila

Intercambia la carta que está en la posición index por la nueva carta que se proporciona y devuelve la pila ajustada. Ten en cuenta que esto modificará el slice de entrada, que es el comportamiento esperado.

index := 2
newCard := 6
cards := SetItem([]int{1, 2, 4, 1}, index, newCard)
fmt.Println(cards)
// Output: [1 2 6 1]

Si el índice está fuera de los límites (es decir, si es negativo o está después del final de la pila), queremos agregar la nueva carta al final de la pila:

index := -1
newCard := 6
cards := SetItem([]int{1, 2, 4, 1}, index, newCard)
fmt.Println(cards)
// Output: [1 2 4 1 6]

4. Agrega cartas al inicio de la pila

Agrega la(s) carta(s) especificada(s) en el parámetro value al inicio de la pila.

slice := []int{3, 2, 6, 4, 8}
cards := PrependItems(slice, 5, 1)
fmt.Println(cards)
// Output: [5 1 3 2 6 4 8]

Si no se proporciona ningún argumento para el parámetro value, el resultado es igual al slice original.

slice := []int{3, 2, 6, 4, 8}
cards := PrependItems(slice)
fmt.Println(cards)
// Output: [3 2 6 4 8]

5. Elimina una carta de la pila

Elimina la carta que está en la posición index de la pila y devuelve la pila. Ten en cuenta que esto puede modificar el slice de entrada, lo cual está bien.

cards := RemoveItem([]int{3, 2, 6, 4, 8}, 2)
fmt.Println(cards)
// Output: [3 2 4 8]

Si el índice está fuera de los límites (es decir, si es negativo o está después del final de la pila), queremos dejar la pila sin cambios:

cards := RemoveItem([]int{3, 2, 6, 4, 8}, 11)
fmt.Println(cards)
// Output: [3 2 6 4 8]
Editar en GitHub El enlace se abre en una ventana o una pestaña nuevas
Go Exercism

¿Todo listo para empezar Trucos con cartas?

Regístrate en Exercism para aprender y dominar Go con 34 conceptos165 ejercicios y mentoría humana real, todo gratis.