Los maps en Go son estructuras de datos clave-valor que nos permiten acceder a un valor específico utilizando una llave única. Imagina un estacionamiento en el que cada puesto tiene un número asignado; para acceder a un vehículo, necesitas saber la clave asociada, que es el número de estacionamiento. En otros lenguajes como Python, estas estructuras se conocen como diccionarios. Conozcamos más sobre cómo funcionan los maps en Go.
¿Cómo se crea un map en Go?
Crear un map en Go es un proceso sencillo gracias al uso del keyword make. Comenzamos declarando nuestro map, que puede almacenar las edades de varias personas. Aquí te mostramos cómo hacerlo:
m :=make(map[string]int)
En este fragmento, map[string]int define un map cuya clave es de tipo string y el valor es de tipo int. A continuación, añadimos algunos valores:
m["José"]=14m["Pepito"]=20
¿Cómo imprimimos un map?
Para visualizar el contenido del map, simplemente lo imprimimos en consola. Al hacerlo, notamos que los elementos se separan por espacios en lugar de comas, algo característico de los maps en Go:
fmt.Println(m)// Salida: map[José:14 Pepito:20]
¿Cómo recorremos un map?
Para recorrer un map en Go, utilizamos un bucle for combinado con range, que nos permite iterar sobre cada clave y valor en el map:
for key, value :=range m { fmt.Println(key, value)}
Es importante destacar que el orden de los elementos en un map es aleatorio debido a su naturaleza concurrente. Si necesitas mantener el orden original, considera usar slices junto con los conocimientos previos de 'slicing'.
¿Cómo accedemos a un valor específico?
Si queremos obtener un valor específico, simplemente accedemos a través de la clave correspondiente, como en el siguiente ejemplo:
value := m["José"]fmt.Println(value)// Salida: 14
¿Qué sucede si accedemos a una clave inexistente?
Al acceder a una clave que no existe, Go retorna el valor cero correspondiente al tipo de dato del map. Por ejemplo, si buscamos una clave no almacenada como en el caso de "Joseph", obtendremos un cero:
value := m["Joseph"]fmt.Println(value)// Salida: 0
Para abordar esta situación, se puede utilizar una segunda variable llamada ok, que indica si la clave existe en el map:
value, ok := m["Joseph"]fmt.Println(value, ok)// Salida: 0 false
Si la clave existe, ok será true; en caso contrario, será false. Esta propiedad resulta esencial para confirmar la presencia de un elemento dentro del map.
¿Por qué elegir maps en Go?
Los maps son estructuras eficientes en Go, especialmente cuando trabajamos con listas relacionadas. Su implementación nativa de concurrencia permite realizar operaciones de manera más fluida y eficaz que las alternativas como slices o arrays.
El conocimiento de maps es fundamental para abordar estructuras de datos complejas y optimizar nuestras aplicaciones. ¡Sigue aprendiendo y explorando el fascinante mundo de Go!
Hay que recordar que los json, diccionaros, maps no son más que un hash map así que sin importar el nombre tienen el mismo uso y funcionamiento
La estructura de datos MAP son más eficientes que los Array o Slices, ya que usan de forma nativa concurrencia para ejecutar las operaciones.
No conozco la implementación de HASH´s de Go, pero, esto puede crear confusión.
Los maps/hash son más eficientes según el caso de uso, si conoces el KEY siempre será más eficiente usar un MAP, debido a que el tiempo de acceso es EN PROMEDIO constante (O(1)) para todos los keys independientemente del tamaño del MAP.
Si solo necesitas iterar sobre un conjunto de elementos, siempre es mejor alternativa usar un Array.
Arrays y Hashes, son bastante similares en memoria, los hashes son en resumen un hack para crear arreglos en los que podemos definir un KEY distinto a un índice entero.
Este es un muy buen artículo para conocer más de los hashes, aunque usa Python para los ejemplos:
package main
import"fmt"funcmain(){//MAPS//Declarationvar map_1 =map[string]int32{"Car":50000,"House":20000,"Computer":1000,} fmt.Println(map_1)//Another type of declaration map_2 :=make(map[int]int) map_2[10]=1 map_2[12]=4 map_2[8]=5 map_2[11]=2//Displaying a mapfor i, v :=range map_2 { fmt.Println(i,"=", v)//There is no order at the momento of displaying a map}//Knowing if a value exist//If we display map_1["Car"] it will show the value value := map_1["Car"] fmt.Println(value)//But what if it doesn't exist value = map_1["aasd"] fmt.Println(value)//It will show zero value, ok := map_1["aasd"]//If we want to know if it exists, it must be done with the second returing value//it will return a bool depending on if exists or not fmt.Println(value, ok)}
Crack!
😎
package main
import"fmt"func main(){m:=make(map[string]int) m["Jose"]=14 m["Pepito"]=20 value,ok:= m["Jose"] fmt.Println(value, ok)}
para eliminar un elemento nada más es con delete: delete(m, "Pepito")
Buen aporte!
Ejemplo de uso [maps]:
Se diseñó una pequeña BD de nombre usuario. Esta base de datos contiene cuatro índices donde llaves son nombres y valores respectivamente la edad del usuario. Entonces:
var usuario =map[string]int{"Luis":17,"Micaela":18,"Ian":16,"Jorge":22,}
Realizamos un bucle sujeto a la condición de que si la edad del usuario es mayor o igual a 18, indique junto al nombre del usuario, un mensaje que afirme dicha cumplida condición. De lo contrario, que indique que este no es mayor de edad:
// [...]funcmain(){for nombre, edad :=range usuario{if edad >=18{ fmt.Printf("%s es mayor de edad \n", nombre)}else{ fmt.Printf("%s es menor de edad \n", nombre)}}}
Que comportamiento tan raro tener que usar una segunda variable para saber si el dato no existe en el map
Es comprensible, pero de igualmente analizando otros lenguajes para saber si existe un valor dentro del Map, tienes que adicionar logicas y en ocaciones hasta complejas, como es el caso de la clase ya vimos de palindromos , en el que para revertir el valor tiene que recorrer inversamente y suma a otros elementos como slice jajajaj.
Excelente aporte master
La clase en código:
package main
import"fmt"func main(){ fmt.Println() fmt.Println("====================================================") fmt.Println("Llave valor con Maps (también llamados diccionarios)") fmt.Println("====================================================") fmt.Println() fmt.Println("Forma recomendada de inicializar el Map:\nmapConMake := make(map[string]int)")mapConMake:=make(map[string]int) fmt.Println("Impresion:", mapConMake) fmt.Println() fmt.Println("Hay otro par de formas de inicializar que quedan en el código después de este comentario.") fmt.Println()var mapInicializado2Pasos map[string]int
mapInicializado2Pasos = map[string]int{"init":-1}mapInicializado1Paso:= map[string]int{"abc":1} fmt.Println("Ejemplo: mapInicializado1Paso=", mapInicializado1Paso) fmt.Println() fmt.Println("La asignación de valores es tan sencillo como:\nmapInicializado2Pasos[\"valor_wan\"] = 1") fmt.Println() mapInicializado2Pasos["valor_wan"]=1 mapInicializado2Pasos["valor_two"]=2 fmt.Println() fmt.Println("La impresión directa del Map muestra los pares key-value separados por un espacio vacío de los demás:\n", mapInicializado2Pasos) fmt.Println() fmt.Println("Para recorrer el Mapa se puede usar el FOR-range, igual que con los slices:") fmt.Println() fmt.Println("for indice, valor := range mapInicializado2Pasos { fmt.Println(\"clave-valor >>>\", indice, valor) }") fmt.Println() fmt.Println("Lo que imprime:") fmt.Println()for indice,valor:= range mapInicializado2Pasos { fmt.Println("clave-valor >>>", indice, valor)} fmt.Println() fmt.Println("Nota: La ejecución anterior es concurrente, por lo que la info no se imprime en órden.") fmt.Println() fmt.Println("Extraer un valor solo es cuestión de hacer:") fmt.Println("mapInicializado2Pasos[\"valor_wan\"]\nque da el valor:", mapInicializado2Pasos["valor_wan"]) fmt.Println() fmt.Println("Si no existe nada en el mapa para el 'key' simplemente se devuelve un 'zero value'.") fmt.Println() fmt.Println("Hay una forma mas certera, booleana para saber si existe o no el valor:") fmt.Println("valor, existe := mapInicializado2Pasos[\"key_falsa\"]") fmt.Println() valor,existe:= mapInicializado2Pasos["key_falsa"] fmt.Printf("Lo que entrega: valor=%d, existe=%t", valor, existe) fmt.Println() fmt.Println()}
¿Cómo declararías un map en Go que según el año guarde el nombre de los graduados del Curso?
Esta es mi respuesta: make(map[int][]string)
Pero me dice que es incorrecta, ¿por qué?
No logro ver mi error
durante el minuto 3:00 el profesor menciona que los maps son accedidos de forma concurrente en Go, pero no he encontrado esa afirmación en internet ni en el blog de do.dev https://go.dev/blog/maps
En qué se basa en esa afirmación o si podría extender la explicación del funcionamiento de los maps de Go
The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If a map entry that has not yet been reached is removed during iteration, the corresponding iteration value will not be produced. If a map entry is created during iteration, that entry may be produced during the iteration or may be skipped. The choice may vary for each entry created and from one iteration to the next. If the map is nil, the number of iterations is 0.
¿Qué es concurrencia?
Clase 20: Llave valor con Maps
Los maps/hash son más eficientes según el caso de uso, si conoces el KEY siempre será más eficiente usar un MAP, debido a que el tiempo de acceso es EN PROMEDIO constante (O(1)) para todos los keys independientemente del tamaño del MAP.
Map son diccionarios en GO
Se usa para manejar valores constantes
Hay que tener cuidado con el recorrido ya que es concurrente se puede ejecutar de forma aleatoria
Si solo necesitas iterar sobre un conjunto de elementos, siempre es mejor alternativa usar un Array.
Usa concurrencia de manera nativa
Arrays y Hashes, son bastante similares en memoria, los hashes son en resumen un hack para crear arreglos en los que podemos definir un KEY distinto a un índice entero.
Este es un muy buen artículo para conocer más de los hashes, aunque usa Python para los ejemplos: Articulo
Fuente:
Víctor Hugo Villalobos Balzán
//Declaración 1 Forma temperature:= map[string]int{"Earth":15,"Mars":-65,}// Declaración forma 2 m:=make(map[string]int)m["Jose"]=25m["Maria"]=20fmt.Println(m)for i,v:= range m{ fmt.Println(i,v)}//Encotrar vaor value,ok:= m[Josep]fmt.Println(value, ok)
Los maps son más eficientes que los arrays y slices** ya que nativamente implementan concurrencia** para interactuar con las operaciones que se hacen con el map, por lo tanto, no debemos preocuparnos por el orden en que se ingresaron los datos, más bien debemos preocuparnos porque la dupla KEY,VALUE exista o no y en base a eso hacer operaciones con los elementos del map.
package main
import (
"fmt"
"strings"
)
func isPalindromo(text string) {
var textReverse string
fori:=len(text)-1; i >=0; i--{ textReverse +=string(text[i])}if strings.ToLower(textReverse)== strings.ToLower(text){ fmt.Println(text," Es un palíndromo")}else{ fmt.Println(text," No es un palíndromo")}
package main
import"fmt"func main(){m:=make(map[string]int) m["Jose"]=14 m["Pepito"]=20 fmt.Println(m)// Recorrer un mapfor i,v:= range m { fmt.Printf("%s tiene %d años\n", i, v)}// Encontrar un valor value,ok:= m["Jose"] fmt.Println(value, ok)}
Buen día comunidad !
Tengo una duda, el "ok", que el profesor utiliza para encontrar el valor, se puede considerar una palabra reservada de golang?
No, go tiene la capacidad de retornar más de un solo valor al ejecutar funciones, en este caso "value" es el primer valor retornado y "ok" el segundo, pero "ok" puede tener cualquier otro nombre, también recuerda que las palabras reservadas no se pueden usar como variables
Crear un map con la información de dos arreglos de la misma longitud, En que momento esto sería útil?
package main
import("fmt""strings")func main(){var nombre =[3]string{"Jose","Alex","Pablo"}var edades =[3]int{24,22,28}m:=make(map[string]int)iflen(nombre)==len(edades){fori:= range nombre { m[strings.ToLower(nombre[i])]= edades[i]}} fmt.Printf("El mapa con información de dos arreglos \n%v\n", m)}
por ejemplo para acceder a la edad de una persona sabiendo su nombre. La llave es el nombre de la persona y la edad es el valor. Por lo general es útil cuando el índice de búsqueda no es un número entero sino un string o valores float.
Buenas. Se puede tener dos tipos de valores en el map, por ejemplo int y string?
Hola Fernando! :D
Sí puedes tener dos tipos de datos distintos en el key y el value. Sin embargo todos los keys deben de ser de un tipo y los value también deben ser todos del mismo tipo