Sebastian Gomez
Arreglos y Ciclos en Go
Arreglos en Go
Los arreglos en Go son una estructura de datos que se usa para almacenar un conjunto de valores del mismo tipo. Un arreglo es una secuencia ordenada de elementos que comparten el mismo tipo. En Go un arreglo tiene un tamaño fijo que se define en tiempo de compilación.
Por ejemplo, el siguiente código crea un arreglo de enteros de tamaño 3:
var arr [3]intPor lo tanto, como máximo puede tener 3 elementos de tipo entero.
Ahora bien, muchas veces no sabemos de antemano cuántos elementos vamos a necesitar, y para eso Go tiene los slices. Un slice se escribe []T (sin un número entre los corchetes) y representa una vista de tamaño variable sobre una secuencia de elementos. Esta es la distinción clave: [N]T es un arreglo de tamaño fijo, mientras que []T es un slice, que puede crecer y encoger. Un slice se declara así:
// Un slice de strings (tamaño variable)
var arr2 []stringLos elementos de un arreglo se pueden acceder usando su índice, que es el número de la posición del elemento en el arreglo. Los índices comienzan desde 0. Por ejemplo, el siguiente código asigna el valor 5 al primer elemento del arreglo anterior:
arr[0] = 5Los arreglos también se pueden inicializar con valores predefinidos. Por ejemplo, el siguiente código crea un arreglo de enteros de tamaño 3 con los valores 5, 10 y 15:
var arr = [3]int{5, 10, 15}Go nos permite insertar elementos despues del último elemento mediante la función append, pero solo en los slices. En los arreglos de tamaño fijo solo podemos asignar valores utilizando el índice.
// Así podemos agregar elementos a un slice
arr2 = append(arr2, "hola")Debemos tener algunas consideraciones, veamos el siguiente ejemplo:
package main
import "fmt"
func main() {
var arr [3]int
arr[0] = 5
fmt.Println(arr)
// Esto imprime [5 0 0]
// Esto no es permitido porque arr es un arreglo de tamaño fijo, no un slice
// arr = append(arr, 3)
// Un slice de strings (tamaño variable)
var arr2 []string
// Así podemos agregar elementos al slice
arr2 = append(arr2, "hola")
fmt.Println(arr2)
// Si el índice 88 aún no se ha llenado, la siguiente línea provoca un panic en tiempo de ejecución
// arr2[88] = "helloworld"
fmt.Println(arr2)
}Acceder a los valores de un arreglo cuando este es muy grande empieza a causar problemas, así que es ahí donde las estructuras cíclicas empiezan a cobrar importancia, por tanto vale la pena estudiarlas.
Estructuras cíclicas en Go
### Estructura For
El ciclo for es el ciclo más comúnmente usado en Go. Se usa para iterar sobre una secuencia de elementos, basándose en condiciones. La sintaxis de for en Go es la siguiente:
for [inicialización]; [condición]; [incremento] { // código a ejecutar }+---------------------+
| Ciclo For |
+---------------------+
| |
| Inicialización | (Opcional)
| for i := 0; |
| |
+---------------------+
| |
| Condición | (Obligatorio para ciclos con condición)
| i < 10; |
| |
+---------------------+
| |
| Post-Ejecución | (Opcional)
| i++ |
| |
+---------------------+
| |
| Bloque de |
| Código | (El código que se ejecuta en cada iteración)
| |
+---------------------+En su forma más simple, una sentencia for especifica la ejecución repetida de un bloque mientras una condición booleana se evalúe como verdadera. La condición se evalúa antes de cada iteración. Si la condición está ausente, es equivalente al valor booleano verdadero.
- Condición única:
for a < b { a *= 2 }ejecuta el bloque mientrasasea menor queb. - Cláusula for:
for i:= 0; i < 10; i++ { f(i) }inicializaien 0, y ejecutaf(i)mientrasisea menor que 10, incrementandoien una unidad cada iteración. - Cláusula range: se usa para iterar sobre los elementos de una estructura de datos como un arreglo o un slice.
package main
import "fmt"
func main() {
var arr = [3]int{5, 10, 15}
// Ambos bloques son similares: i contiene el índice del arreglo
// y v contiene el valor del elemento del arreglo
for i, v := range arr {
fmt.Println(i, v)
}
for i := 0; i < len(arr); i++ {
fmt.Println(i, arr[i])
}
/* En este caso, en ambos ciclos se imprimirá:
0 5
1 10
2 15
*/
}Este es el enlace a la documentación oficial de Go que habla sobre el ciclo for: go.dev/ref/spec#For_statements.
### Ciclo while
El ciclo while es una estructura de control que se usa para ejecutar un bloque de código repetidamente mientras una condición se cumpla. Go no tiene definida la palabra while y su comportamiento se logra a través de la palabra for del lenguaje.
Normalmente en otros lenguajes como Java, JavaScript y C esta sería la sintaxis:
while [condición] { // código a ejecutar }pero en Go sería:
for [condición] { // código a ejecutar }Un ejemplo de su uso sería:
func ejemploCicloWhile() {
// Declarando una variable para contar
var i int = 0
// Usando el ciclo for para iterar 5 veces como si fuera un while
for i < 5 {
fmt.Println("Contador:", i)
i++
}
}El código anterior imprimirá lo siguiente:
Contador: 0
Contador: 1
Contador: 2
Contador: 3
Contador: 4### Ciclo do while
El ciclo do while es una estructura de control que se usa para ejecutar un bloque de código repetidamente hasta que una condición se cumpla, pero ejecutando el primer bloque de código antes de la evaluación de su condición. Su sintaxis es:
do { // código a ejecutar } while [condición];Pero como sabrás, en Go no existe la palabra while ni mucho menos do, por tanto debemos recurrir al for para emular este comportamiento. Un ejemplo de su uso sería:
var j int = 0
// Emulación del ciclo do-while
for {
fmt.Println("Contador:", j)
j++
if j > 4 {
break
}
}El código anterior imprimirá lo siguiente:
Contador: 0
Contador: 1
Contador: 2
Contador: 3
Contador: 4Nota: La diferencia principal entre un ciclo while y un ciclo do-while radica en cuándo se evalúa la condición para la ejecución del bucle. En ambos casos se trata de estructuras de control de flujo utilizadas para repetir un bloque de código basado en una condición, pero la manera en que manejan esta condición difiere.
- Uso típico del while: cuando quieres repetir un bloque de código mientras una condición sea verdadera, pero no es necesario que el bloque se ejecute al menos una vez.
- Uso típico del do while: cuando necesitas que el bloque de código se ejecute al menos una vez antes de evaluar si el bucle debe continuar.
Pero recuerda que las palabras while y do no existen en Go, por tanto debes alcanzar este comportamiento usando for.
Operaciones sobre arreglos en Go
A continuación veamos las operaciones más básicas sobre los arreglos, que consistirán en añadir y borrar elementos, encontrar el índice de un elemento y ordenar los arreglos de manera ascendente y descendente:
func operacionesArreglos() {
// Creamos un slice de enteros
numeros := []int{1, 2, 3}
// Agregamos un elemento al slice
numeros = append(numeros, 4)
fmt.Println(numeros) // [1, 2, 3, 4]
// Eliminar el último elemento
numeros = numeros[:len(numeros)-1]
fmt.Println(numeros) // [1, 2, 3]
// Eliminar el primer elemento
numeros = numeros[1:]
fmt.Println(numeros) // [2, 3]
// Eliminar el elemento en la posición 1
numeros = append(numeros[:1], numeros[2:]...)
fmt.Println(numeros) // [2]
// Eliminar el elemento en la posición 0
numeros = append(numeros[:0], numeros[1:]...)
fmt.Println(numeros) // []
// Volvamos a llenar el slice con 5 números
numeros = []int{1, 6, 3, 4, 2}
// Buscar el elemento 3 en el slice
index := 0
for index < len(numeros) {
if numeros[index] == 3 {
break
}
index++
}
fmt.Println(index) // 2
// Ordenar el arreglo de mayor a menor (descendente)
ordenarMayor(numeros, len(numeros))
// Ordenar el arreglo de menor a mayor (ascendente)
ordenarMenor(numeros, len(numeros))
}
/* La función ordenarMayor() toma el slice y ordena sus elementos de mayor a menor.
Recibe dos argumentos: el primero es un slice de tipo int y el segundo es la cantidad
de elementos, que también es de tipo int. */
func ordenarMayor(listNum []int, Cant int) {
tmp := 0
for x := 0; x < Cant; x++ {
for y := 0; y < Cant; y++ {
if listNum[x] > listNum[y] {
tmp = listNum[x]
listNum[x] = listNum[y]
listNum[y] = tmp
}
}
}
fmt.Print("\nArreglo ordenado de mayor a menor: ")
for i := 0; i < Cant; i++ {
fmt.Print("[", listNum[i], "]")
}
fmt.Println()
}
func ordenarMenor(listNum []int, Cant int) {
tmp := 0
for x := 0; x < Cant; x++ {
for y := 0; y < Cant; y++ {
if listNum[x] < listNum[y] {
tmp = listNum[y]
listNum[y] = listNum[x]
listNum[x] = tmp
}
}
}
fmt.Print("\nArreglo ordenado de menor a mayor: ")
for i := 0; i < Cant; i++ {
fmt.Print("[", listNum[i], "]")
}
fmt.Println()
}Nota: estos ordenarMayor / ordenarMenor son ordenamientos hechos a mano con dos ciclos anidados, es decir tienen complejidad O(n²) y comparaciones de más. Son útiles solo con fines educativos. En código real te recomiendo usar sort.Ints de la librería estándar (lo verás en el ejercicio 5), que es mucho más eficiente.
Diferencia entre = y :=
En Go, los operadores = y := tienen propósitos diferentes y se usan en distintos contextos.
Asignación `=`: se utiliza para asignar valores a variables ya existentes. Es decir, se usa cuando la variable ha sido previamente declarada y solo necesita que se le asigne (o reasigne) un valor.
var x int
x = 10 // Asignando el valor 10 a la variable xDeclaración corta `:=`: es una forma abreviada y conveniente en Go para declarar y asignar una variable en una sola línea. Este operador declara la variable con el tipo de dato inferido del valor asignado, y simultáneamente le asigna dicho valor. Se utiliza cuando se crea una nueva variable, y Go automáticamente infiere el tipo basándose en el valor asignado.
x := 10 // Declara x como int y asigna el valor 10Veamos algunos ejemplos de uso correcto e incorrecto:
// Uso correcto de =
var a int
a = 5 // Correcto, porque a ya fue declarada
// Uso incorrecto de =
a = 5 // Incorrecto si a no ha sido declarada previamente
// Uso correcto de :=
a := 5 // Correcto, declara a como int y le asigna 5
// Uso incorrecto de :=
var a int
a := 5 // Incorrecto, a ya fue declaradaEn resumen, = se usa para asignar valores a variables ya declaradas, mientras que := sirve para declarar nuevas variables y asignarles valores en un solo paso, con el tipo determinado automáticamente por el valor asignado.
Ejercicios resueltos para practicar
A continuación se presentan 10 ejercicios clásicos con arreglos en Go y su respectiva solución, explicada paso a paso:
1. Escriba un programa en Go para imprimir todos los elementos de un arreglo:
package main
import "fmt"
func main() {
// declarar arreglo
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// iterar por el arreglo
for _, num := range arr {
fmt.Println(num)
}
}2. Escriba un programa en Go para encontrar la suma de todos los números de un arreglo:
package main
import "fmt"
func main() {
// declarar arreglo
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// inicializar la suma en 0
sum := 0
// iterar por el arreglo
for _, num := range arr {
sum += num
}
fmt.Println("La suma de los elementos del arreglo es", sum)
}3. Escriba un programa en Go para encontrar el máximo de un arreglo:
package main
import "fmt"
func main() {
// declarar arreglo
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// inicializar el máximo con el primer elemento del arreglo
// (importante: no lo inicialices en 0, porque con números negativos
// devolvería 0, que no está en el arreglo)
max := arr[0]
// iterar desde el segundo elemento
for _, num := range arr[1:] {
if num > max {
max = num
}
}
fmt.Println("El elemento máximo del arreglo es", max)
}4. Escriba un programa en Go para encontrar el índice de un elemento en un arreglo:
package main
import "fmt"
func main() {
// declarar arreglo
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// declarar el elemento a buscar
element := 4
// inicializar el índice
index := -1
// iterar por el arreglo
for i, num := range arr {
if num == element {
index = i
break
}
}
fmt.Println("El índice del elemento", element, "es", index)
}5. Escriba un programa en Go para ordenar los elementos de un arreglo:
package main
import (
"fmt"
"sort"
)
func main() {
// declarar arreglo
arr := []int{3, 6, 2, 1, 4, 9, 7, 8, 5, 10}
// ordenar el arreglo
sort.Ints(arr)
fmt.Println("Arreglo ordenado:", arr)
}6. Escriba un programa en Go para eliminar un elemento de un arreglo:
package main
import "fmt"
func main() {
// declarar arreglo
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// declarar el elemento a eliminar
element := 5
// inicializar el índice
index := -1
// iterar por el arreglo
for i, num := range arr {
if num == element {
index = i
break
}
}
// eliminar elemento del arreglo
if index != -1 {
arr = append(arr[:index], arr[index+1:]...)
}
fmt.Println("Arreglo después de eliminar elemento:", arr)
}7. Escriba un programa en Go para contar el número de veces que se repite un elemento en un arreglo:
package main
import "fmt"
func main() {
// declarar arreglo
arr := []int{1, 2, 3, 1, 4, 1, 5, 6, 7, 8, 9, 10, 1}
// declarar el elemento a buscar
element := 1
// inicializar el contador
count := 0
// iterar por el arreglo
for _, num := range arr {
if num == element {
count++
}
}
fmt.Println("El elemento", element, "se repite", count, "veces.")
}8. Escriba un programa en Go para insertar un elemento en una posición específica de un arreglo:
package main
import "fmt"
func main() {
// declarar arreglo
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// declarar el elemento y la posición
element := 11
position := 5
// insertar el elemento
arr = append(arr, 0)
copy(arr[position+1:], arr[position:])
arr[position] = element
fmt.Println("Arreglo después de insertar elemento:", arr)
}9. Escriba un programa en Go para invertir los elementos de un arreglo:
package main
import "fmt"
func main() {
// declarar arreglo
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// invertir los elementos
for i, j := 0, len(arr)-1; i < j; i, j = i+1, j-1 {
arr[i], arr[j] = arr[j], arr[i]
}
fmt.Println("Arreglo invertido:", arr)
}10. Escriba un programa en Go para eliminar los elementos duplicados de un arreglo:
package main
import "fmt"
func main() {
// declarar arreglo
arr := []int{1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 9, 10}
// inicializar un nuevo slice
newArr := []int{}
// iterar por el arreglo
for _, num := range arr {
// verificar si el elemento ya existe en el nuevo slice
isExist := false
for _, newNum := range newArr {
if num == newNum {
isExist = true
break
}
}
// agregar el elemento si no existe
if !isExist {
newArr = append(newArr, num)
}
}
fmt.Println("Arreglo sin elementos duplicados:", newArr)
}Ejercicios propuestos
A continuación te dejo 10 ejercicios más para que practiques los ciclos en Go y envíes la solución como un Pull request a este repositorio: Go Para Principiantes.
- Escriba un programa en Go que imprima los primeros 10 números naturales.
- Escriba un programa en Go que calcule la suma de los primeros 10 números naturales.
- Escriba un programa en Go que calcule el promedio de los primeros 10 números naturales.
- Escriba un programa en Go que calcule el factorial de un número dado.
- Escriba un programa en Go que determine si un número dado es par o impar.
- Escriba un programa en Go que determine si un número dado es primo.
- Escriba un programa en Go que imprima los números del 1 al 100.
- Escriba un programa en Go que determine la suma de los números del 1 al 100.
- Escriba un programa en Go que determine si un número dado está dentro de un rango dado.
- Escriba un programa en Go que calcule el número de dígitos de un número dado.
Resumen en 3 puntos
- En Go,
[N]Tes un arreglo de tamaño fijo y[]Tes un slice de tamaño variable; solo los slices soportanappend. - Go solo tiene la palabra
for, con ella se cubren los casos de while y do while que en otros lenguajes son palabras separadas. - Usa
:=para declarar y asignar una variable nueva (con tipo inferido) y=para reasignar una variable que ya existe.
Eso es todo, espero que este post te sea de utilidad y lo puedas aplicar a algún proyecto que tengas en mente, o que simplemente te haya ayudado a entender mejor los arreglos y los ciclos en Go.
Déjame un comentario si te sirvió, si quieres añadir alguna opinión o si tienes alguna duda. Y recuerda que si te gustó, también puedes compartirlo usando los links a las redes sociales aquí abajo. ¡Buena suerte!
Sebastian Gomez
Creador de contenido principalmente acerca de tecnología.