25 - Estructura de datos tipo maps

Hasta ahora hemos presentado dos estructuras de datos en el lenguaje Go: arrays y slices. Ahora presentaremos y comenzaremos a utilizar la estructura de datos tipo maps.

La estructura de datos tipo maps utiliza una clave para acceder a un valor. El subíndice puede ser un entero, un string etc. (en general cualquier tipo de dato comparable)

Podemos relacionar la estructura de tipo maps con conceptos que conocemos:

  • Un diccionario tradicional que conocemos podemos utilizar un maps para representarlo. La clave sería la palabra y el valor sería la definición de dicha palabra.
  • Una agenda personal también la podemos representar como un diccionario. La fecha sería la clave y las actividades de dicha fecha sería el valor.
  • Un conjunto de usuarios de un sitio web podemos almacenarlo en un diccionario. El nombre de usuario sería la clave y como valor podríamos almacenar su mail, clave, fechas de login etc.

Hay muchos problemas de la realidad que se pueden representar mediante un maps.

Un maps es una estructura de datos mutable es decir podemos agregar elementos, modificar y borrar.

Problema 1:

Definir un maps que almacene los nombres de paises como clave y como valor la cantidad de habitantes. Imprimir luego el maps completo y la cantidad de habitantes de un país en particular.

Programa: ejercicio119.go

package main

import "fmt"

func main() {
    paises := make(map[string]int)
    paises["argentina"] = 40000000
    paises["españa"] = 46000000
    paises["brasil"] = 190000000
    paises["uruguay"] = 3400000
    fmt.Println(paises)
    fmt.Println("La cantidad de habitantes de españa es:", paises["españa"])
}

Para crear un maps utilizamos la función make indicando la palabra clave map y seguidamente entre corchetes el tipo de dato de la clave del maps y fuera de los corchetes el tipo de dato del valor del maps:

    paises := make(map[string]int)

En nuestro problema como los nombres de países son cadenas de caracteres utilizamos como clave un string y el valor que se almacena para cada nombre de país es un número de habitantes.

Para cargar elementos al maps del lado izquierdo del operador de asignación disponemos el nombre del maps y como subíndice un nombre para la clave, y del lado derecho del operador de asignación el valor que se almacena en el maps para dicha clave:

    paises["argentina"] = 40000000

Si cargamos un valor para una clave ya existente se modifica el valor actual:

    paises["argentina"] = 39000000

El maps crece en forma dinámica a medida que agregamos elementos.

Si queremos acceder a un valor para una clave utilizamos la sintaxis:

    fmt.Println("La cantidad de habitantes de españa es:", paises["españa"])

Si tratamos de acceder a un valor para una clave inexistente luego nos retorna el 0 (no se genera error):

    fmt.Println("La cantidad de habitantes de eeuu es:", paises["eeuu"])

Una forma alternativa para definir un maps con una serie de valores iniciales sin utilizar la función make es:

Programa: ejercicio120.go

package main

import "fmt"

func main() {
    paises := map[string]int{
        "argentina" : 40000000,
        "españa"    : 46000000,
        "brasil"    : 190000000,
        "uruguay"   : 3400000,
    }
    fmt.Println(paises)
    fmt.Println("La cantidad de habitantes de españa es:", paises["españa"])
}

Verificar si existe una clave en el maps.

Problema 2:

Definir un maps que almacene los nombres de paises como clave y como valor la cantidad de habitantes. Ingresar por teclado un nombre de país y mostrar la cantidad de habitantes o un mensaje indicando que ese país no existe.

Programa: ejercicio121.go

package main

import "fmt"

func main() {
    paises := map[string]int{
        "argentina" : 40000000,
        "españa"    : 46000000,
        "brasil"    : 190000000,
        "uruguay"   : 3400000,
    }
    fmt.Print("Ingrese el nombre de país a consultar:")
    var nom string
    fmt.Scan(&nom)
    cantidad, existe := paises[nom]
    if existe {
        fmt.Println("La cantidad de habitantes:", cantidad)
    } else {
        fmt.Println("No existe un país con dicho nombre")
    }
}

Definimos un maps con una serie de países y cantidad de habitantes:

    paises := map[string]int{
        "argentina" : 40000000,
        "españa"    : 46000000,
        "brasil"    : 190000000,
        "uruguay"   : 3400000,
    }

Solicitamos que el operador ingrese el nombre de un país:

    fmt.Print("Ingrese el nombre de país a consultar:")
    var nom string
    fmt.Scan(&nom)

Cuando accedemos a un elemento del maps retorna: el valor para dicha clave y un valor bool (puede ser true o false):

    cantidad, existe := paises[nom]

Si en al variable existe se almacena un true significa que existe la clave que buscamos:

    if existe {
        fmt.Println("La cantidad de habitantes:", cantidad)
    } else {
        fmt.Println("No existe un país con dicho nombre")
    }

Eliminar elementos de un maps

Se utiliza la función delete. Le pasamos el nombre del maps y la clave a borrar.

Problema 3:

Crear un maps que permita almacenar productos, utilizar como clave el nombre del producto y como valor el precio del mismo.

Desarrollar las funciones de:

1) Cargar productos.
2) Borrado de un producto
3) Listado completo.

Programa: ejercicio122.go

package main

import "fmt"

func cargar(productos map[string]float64) {
    var nom string
    var precio float64
    var opcion string
    for {
        fmt.Print("Ingrese nombre del producto:")
        fmt.Scan(&nom)
        fmt.Print("Ingrese el precio:")
        fmt.Scan(&precio)
        productos[nom] = precio
        fmt.Print("Desea cargar otro producto[s/n]:")
        fmt.Scan(&opcion)
        if opcion=="n" {
            break;
        }
    }
}

func imprimir(productos map[string]float64) {
    fmt.Println(productos)
}

func borrar(productos map[string]float64) {
    var nom string
    fmt.Print("Ingrese el nombre de producto a borrar:")
    fmt.Scan(&nom)
    _, existe := productos[nom]
    if existe {
        delete(productos, nom)
        fmt.Println("Se eliminó el producto")
    } else {
        fmt.Println("No existe")
    }
}

func main() {
    productos := make(map[string]float64)
    cargar(productos)
    imprimir(productos)
    borrar(productos)
    imprimir(productos)
}

En la función main creamos un maps llamado productos con su clave de tipo string (almacena el nombre del producto) y como valor es de tipo float64 ya que almacenamos su precio.

Cuando se pasa un maps a una función si agregamos o eliminamos elementos luego se modifica la variable definida en la main:

func main() {
    productos := make(map[string]float64)
    cargar(productos)
    imprimir(productos)
    borrar(productos)
    imprimir(productos)
}

La función de cargar recibe la referencia del maps y dentro de su algoritmo ingresamos productos y sus precios hasta que el operador no quiera ingresar más:

func cargar(productos map[string]float64) {
    var nom string
    var precio float64
    var opcion string
    for {
        fmt.Print("Ingrese nombre del producto:")
        fmt.Scan(&nom)
        fmt.Print("Ingrese el precio:")
        fmt.Scan(&precio)
        productos[nom] = precio
        fmt.Print("Desea cargar otro producto[s/n]:")
        fmt.Scan(&opcion)
        if opcion=="n" {
            break;
        }
    }
}

La función de imprimir muestra en forma completo el maps:

func imprimir(productos map[string]float64) {
    fmt.Println(productos)
}

La función de borrar solicita el ingreso del nombre de un producto por teclado:

func borrar(productos map[string]float64) {
    var nom string
    fmt.Print("Ingrese el nombre de producto a borrar:")
    fmt.Scan(&nom)

Como no hace falta recuperar el precio disponemos el _ (guión bajo para descartar el precio del producto), nos importa recuperar si existe ese nombre de producto:

    _, existe := productos[nom]

En el caso que exista procedemos a llamar a la función delete pasando el nombre del maps y el nombre de producto a eliminar:

    if existe {
        delete(productos, nom)
        fmt.Println("Se eliminó el producto")
    } else {
        fmt.Println("No existe")
    }
}

Recorrer un maps mediante un for range

Para recorrer un maps y acceder a todas sus claves y valores se utiliza una variante de la estructura repetitiva for.

Programa: ejercicio123.go

package main

import "fmt"

func main() {
    paises := map[string]int{
        "argentina" : 40000000,
        "españa"    : 46000000,
        "brasil"    : 190000000,
        "uruguay"   : 3400000,
    }
    for clave, valor := range paises {
        fmt.Println("Clave:", clave, " Valor:", valor)
    }
}

La sentencia range le sigue el nombre del maps, y retorna dos valores que son almacenados en este ejemplo en las variables clave y valor. Cada iteración del for almacena una clave y valor distinto almacenado en el maps:

    for clave, valor := range paises {
        fmt.Println("Clave:", clave, " Valor:", valor)
    }

Un maps no tiene un orden particular como se almacenan los datos en el mismo.

Problema propuesto

  • Desarrollar una aplicación que nos permita crear un diccionario ingles/castellano (utilizar un maps). La clave es la palabra en ingles y el valor es la palabra en castellano.
    Crear las siguientes funciones:
    1) Cargar el diccionario.
    2) Listado completo del diccionario.
    3) Ingresar por teclado una palabra en ingles y si existe en el diccionario mostrar su traducción.
Solución
ejercicio124.go

package main

import "fmt"

func cargar(diccionario map[string]string) {
    diccionario["red"] = "rojo"
    diccionario["blue"] = "azul"
    diccionario["yellow"] = "amarillo"
    diccionario["green"] = "verde"
}

func imprimir(diccionario map[string]string) {
    for ingles, castellano := range diccionario {
        fmt.Println("Ingles:", ingles," - Castellano:", castellano)
    }
}

func consulta(diccionario map[string]string) {
    var cad string
    fmt.Print("Ingrese la palabra en ingles a consultar:")
    fmt.Scan(&cad)
    castellano, existe := diccionario[cad]
    if existe {
        fmt.Println("Traducción:", castellano)
    } else {
        fmt.Println("No existe la traducción de dicha palabra")
    }
}

func main(){
    diccionario := make(map[string]string)
    cargar(diccionario)
    imprimir(diccionario)
    consulta(diccionario)
}