Ejercicio: Uso de matrices

Completado

Las matrices de Go son una estructura de datos de longitud fija de un tipo determinado. Pueden tener cero o más elementos, y es necesario definir su tamaño al declararlas o inicializarlas. Además, no es posible cambiar su tamaño una vez creadas. Por estos motivos, las matrices no se suelen usar en los programas de Go, aunque son la base de los segmentos y las asignaciones.

Declaración de matrices

Para declarar una matriz en Go, hay que definir el tipo de datos de sus elementos y el número de elementos que puede contener. Luego se puede acceder a cada elemento de la matriz con la notación de subíndice, donde cero es el primer elemento y el último es uno menos que la longitud de la matriz (length - 1).

Por ejemplo, vamos a usar el código siguiente:

package main

import "fmt"

func main() {
    var a [3]int
    a[1] = 10
    fmt.Println(a[0])
    fmt.Println(a[1])
    fmt.Println(a[len(a)-1])
}

Al ejecutar el código anterior, se obtiene el siguiente resultado:

0
10
0

Aunque se ha declarado una matriz, no se obtiene un error al acceder a sus elementos. De manera predeterminada, Go inicializa cada elemento con el tipo de datos predeterminado. En este caso, el valor predeterminado de int es cero, Sin embargo, puede asignar un valor a una posición determinada, como ya hicimos con a[1] = 10. También se puede acceder a ese elemento mediante la misma notación. Además, observe que se ha usado a[0] para referenciar el primer elemento. Para referenciar el último elemento, usamos a[len(a)-1]. La función len es una función integrada de Go para obtener el número de elementos de una matriz, segmento o asignación.

Inicialización de matrices

También puede inicializar una matriz con valores distintos a los predeterminados al declararla. Por ejemplo, puede usar el código siguiente para ver y probar la sintaxis:

package main

import "fmt"

func main() {
    cities := [5]string{"New York", "Paris", "Berlin", "Madrid"}
    fmt.Println("Cities:", cities)
}

Ejecute el código anterior; debería ver este resultado:

Cities: [New York Paris Berlin Madrid ]

Aunque la matriz debería tener cinco elementos, no es necesario asignar un valor a todos. Como se ha visto antes, la última posición presenta una cadena vacía porque es el valor predeterminado de un tipo de datos de cadena.

Puntos suspensivos en matrices

Otra forma de declarar e inicializar una matriz cuando no se sabe cuántas posiciones se van a necesitar, pero sí cuál es el conjunto de elementos de datos, es usar puntos suspensivos (...), como en este ejemplo:

q := [...]int{1, 2, 3}

Vamos a modificar el programa empleado en la sección anterior para usar puntos suspensivos. El código debería tener un aspecto como el de este ejemplo:

package main

import "fmt"

func main() {
    cities := [...]string{"New York", "Paris", "Berlin", "Madrid"}
    fmt.Println("Cities:", cities)
}

Ejecute el código anterior; debería ver un resultado similar, como en este ejemplo:

Cities: [New York Paris Berlin Madrid]

¿Puede ver la diferencia? No hay ninguna cadena vacía al final. La longitud de la matriz viene determinada por las cadenas colocadas al inicializarla. No se reserva memoria que no se sabe si se va a necesitar.

Otra manera interesante de inicializar una matriz es usar puntos suspensivos y especificar únicamente un valor en la última posición. Por ejemplo, use el código siguiente:

package main

import "fmt"

func main() {
    numbers := [...]int{99: -1}
    fmt.Println("First Position:", numbers[0])
    fmt.Println("Last Position:", numbers[99])
    fmt.Println("Length:", len(numbers))
}

Ejecute este código y obtendrá este resultado:

First Position: 0
Last Position: -1
Length: 100

Observe cómo la longitud de la matriz es 100 porque ha especificado un valor en la posición 99ª. La primera posición imprime el valor predeterminado (cero).

Matrices multidimensionales

Go admite las matrices multidimensionales cuando se necesita trabajar con estructuras de datos complejas. Vamos a crear un programa en el que se declare e inicialice una matriz bidimensional. Use el código siguiente:

package main

import "fmt"

func main() {
    var twoD [3][5]int
    for i := 0; i < 3; i++ {
        for j := 0; j < 5; j++ {
            twoD[i][j] = (i + 1) * (j + 1)
        }
        fmt.Println("Row", i, twoD[i])
    }
    fmt.Println("\nAll at once:", twoD)
}

Ejecute el programa anterior; debería ver un resultado como el de este ejemplo:

Row 0 [1 2 3 4 5]
Row 1 [2 4 6 8 10]
Row 2 [3 6 9 12 15]

All at once: [[1 2 3 4 5] [2 4 6 8 10] [3 6 9 12 15]]

Ha declarado una matriz bidimensional que especifica cuántas posiciones tendría la matriz en la segunda dimensión, como esta var twoD [3][5]int. Podría imaginarse esta matriz como una estructura de datos con columnas y filas, como una hoja de cálculo o una matriz. En este punto, todas las posiciones tienen un valor predeterminado de cero. En el bucle for vamos a inicializar cada posición con un patrón de valor diferente en cada fila. Por último, imprima todos sus valores en el terminal.

¿Qué ocurriría si quisiera declarar una matriz tridimensional? Puede adivinar cuál sería la sintaxis, ¿no? Puede hacerlo como en este ejemplo:

package main

import "fmt"

func main() {
    var threeD [3][5][2]int
    for i := 0; i < 3; i++ {
        for j := 0; j < 5; j++ {
            for k := 0; k < 2; k++ {
                threeD[i][j][k] = (i + 1) * (j + 1) * (k + 1)
            }
        }
    }
    fmt.Println("\nAll at once:", threeD)
}

Ejecute el código anterior; debería ver un resultado como el de este ejemplo:

All at once: [[[1 2] [2 4] [3 6] [4 8] [5 10]] [[2 4] [4 8] [6 12] [8 16] [10 20]] [[3 6] [6 12] [9 18] [12 24] [15 30]]]

Si se aplica un formato más legible al resultado, se podría obtener algo parecido a este ejemplo:

All at once: 
[
    [
        [1 2] [2 4] [3 6] [4 8] [5 10]
    ] 
    [
        [2 4] [4 8] [6 12] [8 16] [10 20]
    ] 
    [
        [3 6] [6 12] [9 18] [12 24] [15 30]
    ]
]

Observe cómo cambia la estructura con respecto a una matriz bidimensional. Se pueden seguir agregando más dimensiones según sea necesario, pero por ahora lo vamos a dejar aquí porque hay otros tipos de datos que explorar.