Skip to content

Instantly share code, notes, and snippets.

@hevela

hevela/main.go Secret

Created September 13, 2023 21:50
Show Gist options
  • Save hevela/8c4ce085b58fbec57c38b96a83ad4809 to your computer and use it in GitHub Desktop.
Save hevela/8c4ce085b58fbec57c38b96a83ad4809 to your computer and use it in GitHub Desktop.
Introduction to maps
package main
import (
"fmt"
"sort"
"strings"
)
func main() {
// Introduction to Maps
introToMaps()
// Working with Map Elements
workingWithMapElements()
// Map Operations
mapOperations()
// Iterating Over Maps
loopingThroughMaps()
loopingMapsInOrder()
// Maps and Reference Types:
referenceMaps()
// Map Key and Values of Different Types
complexMaps()
// Map Use Cases
useCases()
// common errors
commonErrors()
// Exercise
urlEncode()
}
func introToMaps() {
// Mapas son una de las estructuras de datos más útiles. La mayoría de los lenguajes de programación
// cuentan con una implementación (Diccionarios en Python, HashMaps en Java, Objetos en Javascript, arreglos asociativos en PHP, etc).
// Son contenedores donde podemos colocar información para después encontrarla fácilmente
// Declaración
// Un mapa en Go luce así: map[KeyType]ValueType
// donde KeyType es un tipo [comparable](https://go.dev/ref/spec#Comparison_operators),
// (boolean, numeric, string, pointer, channel, interface, y structs o arrays que contengan solo estos tipos de valores.
// ValueType puede ser cualquier cosa
var products map[string]float64
fmt.Println(fmt.Sprintf("products is of type %T and its value is %#v", products, products))
fmt.Println(products == nil)
// al leerlo, un mapa nulo (nil) se comporta como un mapa vacío para lecturas,
// pero si se intenta escribir en él, habrá un panic en tiempo de ejecución
fmt.Println(products["non existent key"])
// panic: assignment to entry in nil map
//products["Gorra Mario"] = 99.99
//-----------------
// Inicialización
// Para inicializar un mapa, podemos usar la función _make_
var products2 = make(map[string]float64)
products = map[string]float64{}
products2["Gorra Mario"] = 99.99
products["Gorra Mario"] = 99.99
fmt.Println(fmt.Sprintf("products2 is of type %T and its value is %#v", products2, products2))
// también se pueden inicializar con la sintaxis abreviada
products3 := map[string]float64{}
products3["Gorra Luigi"] = 89.99
fmt.Println(fmt.Sprintf("products3 is of type %T and its value is %#v", products3, products3))
}
func workingWithMapElements() {
// la sintaxis para trabajar con mapas es familiar y sencilla
// inicializando un mapa con valores
account := map[string]string{
"dev": "691484518277",
"qa": "691515518215",
"stg": "632515518875",
}
// asignando valores a un mapa existente
account["prod"] = "369524578943"
fmt.Println(fmt.Sprintf("%#v", account))
// -----------
//// obteniendo valores de un mapa
devAccount := account["dev"]
fmt.Println(fmt.Sprintf("%q", devAccount))
// -----------
//// al acceder a una llave no existente, obtenemos el "zero value" del tipo del valor del mapa
uatAccount := account["uat"]
fmt.Println(fmt.Sprintf("%q", uatAccount))
}
func mapOperations() {
// Go incluye varias funciones que nos ayudan a trabajar con mapas
// Podemos contar las llaves que tiene un mapa
account := map[string]string{
"dev": "691484518277",
"qa": "691515518215",
"stg": "632515518875",
"test": "",
}
fmt.Println("number of keys:", len(account))
// -----------
key := "dev"
//// podemos borrar una llave de un mapa
delete(account, key)
fmt.Println("number of keys:", len(account))
// -----------
//// podemos obtener el valor de un campo/llave de un mapa, pero si no está definido, obtenemos su zero value
value := account[key]
fmt.Println(fmt.Sprintf("the value of map[\"%s\"] is: %q", key, value))
// -----------
//// para revisar la existencia de una llave, usamos una asignación de dos valores
if _, ok := account[key]; !ok {
fmt.Println(fmt.Sprintf("key '%s' not found", key))
return
}
fmt.Println(fmt.Sprintf("the value of map[\"%s\"] is: %q", "test", value))
}
type numberToStr map[int]string
func loopingThroughMaps() {
// Podemos iterar un mapa con un for, usando range.
// Range nos provee una manera de recorrer cada elemento de un iterable por medio de su llave y valor
a := numberToStr{
0: "zero",
1: "one",
2: "two",
3: "three",
4: "four",
5: "five",
6: "six",
7: "seven",
8: "eight",
9: "nine",
10: "ten",
11: "eleven",
12: "twelve",
13: "thirteen",
14: "fourteen",
15: "fifteen",
}
for key, value := range a {
fmt.Println(key, value)
}
// -----------
// El orden de las llaves al iterar un mapa es aleatorio por diseño
// Esto es para incentivar a los desarrolladores a escribir código que no dependa del orden de las llaves
// de un mapa (eliminando el requerimiento de mantener el orden de las llaves)
// También evita que los desarrolladores hagan suposiciones sobre el orden
// Ejercicio: recorrer las llaves de un mapa en orden
}
func loopingMapsInOrder() {
a := numberToStr{
0: "zero",
1: "one",
2: "two",
3: "three",
4: "four",
5: "five",
6: "six",
7: "seven",
8: "eight",
9: "nine",
10: "ten",
11: "eleven",
12: "twelve",
13: "thirteen",
14: "fourteen",
15: "fifteen",
}
// Extract the keys into a slice.
keys := make([]int, 0, len(a))
for key := range a {
keys = append(keys, key)
}
fmt.Println(keys)
// Sort the keys.
sort.Ints(keys)
fmt.Println(keys)
// Iterate through the sorted keys and access the map elements.
for _, key := range keys {
fmt.Printf("%d: %s\n", key, a[key])
}
}
func referenceMaps() {
// Los mapas son un tipo de dato de referencia. Es decir, la variable no contiene la data,
// sino que apunta a la locación de memoria donde están.
// Cuando se asigna una variable de tipo de referencia a otra variable o es pasada como
// argumento a una función, se está copiando la referencia a memoria, no la data
a := numberToStr{
1: "one",
2: "two",
}
b := a
b[1] = "uno"
fmt.Println(b)
fmt.Println(a)
fmt.Println(mapsAreEqual(a, b))
// Ejercicio: copiar un mapa
valueMaps()
}
func valueMaps() {
a := numberToStr{
1: "one",
2: "two",
}
b := copyMap(a)
fmt.Println(b)
fmt.Println(a)
b[1] = "uno"
fmt.Println(mapsAreEqual(a, b))
}
func complexMaps() {
// como fue mencionado, los mapas pueden contener valores de cualquier tipo y llaves de tipos comparables
type person struct {
firstName string
lastName string
}
type address struct {
streetName string
number string
neighborhood string
zipCode string
}
peopleAddresses := map[person][]address{
person{
firstName: "Makko",
lastName: "Vela",
}: []address{
{
streetName: "Evergreen Terrace",
number: "742",
neighborhood: "Henderson",
zipCode: "90210",
},
{
streetName: "Spalding Way",
number: "420",
neighborhood: "Adamsbert",
zipCode: "63637",
},
},
}
makko := person{
firstName: "Makko",
lastName: "Vela",
}
fmt.Println(peopleAddresses[makko])
// -----------
// podemos tener mapas anidados
familyTree := map[string]map[string]string{
"Juan": {
"father": "Miguel",
"mother": "Ana",
},
"María": {
"father": "Alfredo",
"mother": "Guadalupe",
},
}
// Accessing nested map values
fmt.Println("Juan's dad is:", familyTree["Juan"]["father"])
fmt.Println("María's mom is:", familyTree["María"]["mother"])
// -----------
// incluso podemos guardar funciones como valores
type mathOperations map[string]func(a, b float64) float64
calculator := mathOperations{
"suma": func(a, b float64) float64 {
return a + b
},
"resta": func(a, b float64) float64 {
return a - b
},
"multiplicacion": func(a, b float64) float64 {
return a * b
},
"division": func(a, b float64) float64 {
return a / b
},
}
operands := []float64{3.0, 7.0}
for k, _ := range calculator {
result := calculator[k](operands[0], operands[1])
fmt.Println(fmt.Sprintf("el resultado de %s es %f", k, result))
}
}
func copyMap(map1 map[int]string) map[int]string {
newMap := map[int]string{}
for key, value := range map1 {
newMap[key] = value
}
return newMap
}
func useCases() {
// los casos de uso más comunes para usar mapas, son:
// asociación de datos
dictionary := map[string]string{
"map": "a diagram or collection of data showing the spatial arrangement or distribution of something over an area",
}
fmt.Println(dictionary["map"])
// contar coincidencias
song := "Baby Shark, doo-doo, doo-doo, doo-doo, Baby Shark, doo-doo, doo-doo, doo-doo, Baby Shark, doo-doo, doo-doo, doo-doo, Baby Shark"
song = strings.ReplaceAll(song, ",", "")
words := strings.Split(song, " ")
lyricMap := map[string]int{}
for _, word := range words {
if _, found := lyricMap[word]; !found {
lyricMap[word] = 1
continue
}
lyricMap[word]++
}
fmt.Printf("%#v\n", lyricMap)
// cache
cache("key")
cache("key")
// switch
switchMap := map[string]func(a, b float64) float64{
"suma": func(a, b float64) float64 {
return a + b
},
"resta": func(a, b float64) float64 {
return a - b
},
"multiplicacion": func(a, b float64) float64 {
return a * b
},
"division": func(a, b float64) float64 {
return a / b
},
}
fmt.Println(switchMap["suma"](3, 4))
fmt.Println(switchMap["division"](3, 4))
}
func commonErrors() {
// nil map panic
var myMap map[string]string
myMap["value"] = "something"
// key not found
fmt.Printf("%#v\n", myMap["non-existing-key"])
// pass by reference
myMap["key"] = "value"
updateKey(myMap)
fmt.Printf("%#v\n", myMap)
// concurrent access
}
func updateKey(myMap map[string]string) {
myMap["key"] = "some other value"
}
var cacheMap = map[string]int{}
func cache(key string) int {
data, ok := cacheMap[key]
if !ok {
// do some expensive operation here to get `data`
data = 123
cacheMap[key] = data
fmt.Println("expensive operation")
return data
}
fmt.Println("serve from cache")
return data
}
func mapsAreEqual(map1, map2 map[int]string) bool {
// Step 1: Check if the maps have the same length.
if len(map1) != len(map2) {
return false
}
// Step 2: Compare the keys and values of the first map with the second map.
for key, value1 := range map1 {
value2, found := map2[key]
if !found || value1 != value2 {
fmt.Println("found:", found, value1, value2)
return false
}
}
return true
}
type urlValues map[string][]string
// Encode encodes the values into “URL encoded” form
// ("bar=baz&foo=quux") sorted by key.
// Key values are sorted as well.
func (v urlValues) Encode() string {
if v == nil {
return ""
}
uri := ""
keys := make([]string, 0, len(v))
for k := range v {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
vs := v[k]
sort.Strings(vs)
for _, v := range vs {
if len(uri) > 0 {
uri += "&"
}
uri += fmt.Sprintf("%s=%s", k, v)
}
}
return uri
}
func urlEncode() {
urlVals := urlValues{
"status": []string{
"suspended",
"active",
},
"user": []string{
"7123f734-680d-42bc-8c27-aef98e8c5590",
},
"type": []string{
"transfer",
"download",
},
}
uri := urlVals.Encode()
// status=active&status=suspended&type=download&type=transfer&user=7123f734-680d-42bc-8c27-aef98e8c5590
fmt.Println(uri)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment