Tracks
/
Julia
Julia
/
Ejercicios
/
Gestión de bocadillos mecha
Gestión de bocadillos mecha

Gestión de bocadillos mecha

Ejercicio de aprendizaje

Introducción

El concepto Pairs and Dicts trató los fundamentos del tipo diccionario de Julia.

Como los Dict son un tipo de colección importante y de uso frecuente, también existen muchas funciones para manipularlos.

Obtener entradas

La forma más sencilla de obtener una entrada es por su clave (como en muchos lenguajes). Sin embargo, pedir una clave que no existe produce un KeyError.

julia> d = Dict(i => ('a':'c')[i] for i in 1:3)
Dict{Int64, Char} with 3 entries:
  2 => 'b'
  3 => 'c'
  1 => 'a'
julia> d[2]
'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
# missing key
julia> d[4]
ERROR: KeyError: key 4 not found

Podríamos comprobar si la clave existe antes de intentar obtenerla (con algo como haskey(d, 4)), pero puede ser útil obtener directamente un valor predeterminado para las claves que faltan.

Para eso tenemos la función get() y su variante mutadora get!(). La diferencia entre ambas está en si una clave «faltante» se agrega o no al Dict.

julia> get(d, 4, '!')
'!': ASCII/Unicode U+0021 (category Po: Punctuation, other)
# get() leaves Dict unchanged
julia> d
Dict{Int64, Char} with 3 entries:
  2 => 'b'
  3 => 'c'
  1 => 'a'
julia> get!(d, 4, '!')
'!': ASCII/Unicode U+0021 (category Po: Punctuation, other)
# get!() adds new key to Dict
julia> d
Dict{Int64, Char} with 4 entries:
  4 => '!'
  2 => 'b'
  3 => 'c'
  1 => 'a'

En el concepto anterior vimos que delete!() elimina una entrada por su clave. Esto se puede combinar con la obtención del valor usando la función pop!().

julia> d
Dict{Int64, Char} with 4 entries:
  4 => '!'
  2 => 'b'
  3 => 'c'
  1 => 'a'
# popped value is returned
julia> pop!(d, 3)
'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
# Dict is shrunk
julia> d
Dict{Int64, Char} with 3 entries:
  4 => '!'
  2 => 'b'
  1 => 'a'

Iteración

Al iterar sobre un Dict, lo que se obtiene por defecto son pares key => value. Se puede acceder a sus componentes con la nomenclatura habitual .first y .second.

# d is from the previous example
julia> [(kv.first, kv.second) for kv in d]
3-element Vector{Tuple{Int64, Char}}:
 (4, '!')
 (2, 'b')
 (1, 'a')

A menudo queremos usar solo las claves o solo los valores, y eso es fácil.

julia> [k for k in keys(d)]
3-element Vector{Int64}:
 4
 2
 1
julia> [v for v in values(d)]
3-element Vector{Char}:
 '!': ASCII/Unicode U+0021 (category Po: Punctuation, other)
 'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
 'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)

Fusión

Fusionar dos Dict puede ser útil, pero debemos tener claro qué queremos hacer con las claves que aparecen en más de una entrada.

Las funciones merge() y merge!() fusionan una cantidad arbitraria de Dict de izquierda a derecha.

Los valores de las claves que ya existen simplemente se sobrescriben, así que el Dict que está más a la derecha «gana».

julia> d3 = Dict("color" => "red", "shape" => "circle")
Dict{String, String} with 2 entries:
  "shape" => "circle"
  "color" => "red"
julia> d4 = Dict("color" => "blue", "coords" => (3, 2))
Dict{String, Any} with 2 entries:
  "color"  => "blue"
  "coords" => (3, 2)
# color from d3 is lost
julia> merge(d3, d4)
Dict{String, Any} with 3 entries:
  "shape"  => "circle"
  "color"  => "blue"
  "coords" => (3, 2)

Las funciones mergewith() y mergewith!() nos permiten pasar una función como primer argumento para definir cómo se deben fusionar las claves repetidas. La suma es un ejemplo sencillo.

julia> d5 = Dict("color" => "red", "area" => 3)
Dict{String, Any} with 2 entries:
  "area"  => 3
  "color" => "red"
julia> d6 = Dict("shape" => "circle", "area" => 5)
Dict{String, Any} with 2 entries:
  "shape" => "circle"
  "area"  => 5
# area values are added, not overwritten
julia> mergewith(+, d5, d6)
Dict{String, Any} with 3 entries:
  "shape" => "circle"
  "area"  => 8
  "color" => "red"

Ten en cuenta que las funciones mergewith son un buen ejemplo de funciones de orden superior en acción.

Instrucciones

Mecha Munch™, una empresa de automatización de compras de supermercado, acaba de contratarte para trabajar en su app de pedidos. Tu equipo tiene la tarea de construir un MVP (producto mínimo viable) que gestione todas las actividades básicas del carrito de compras y permita a los usuarios agregar, eliminar y ordenar sus pedidos de supermercado. Por suerte, ¡otro equipo se encarga de todo lo relacionado con el dinero y el pago!

1. Agrega artículo(s) al carrito de compras del usuario

El MVP debe permitir que el usuario agregue artículos a su carrito de compras. Puede ser un solo artículo o varios a la vez. Como se trata de un MVP, la cantidad de artículos se indica mediante repeticiones. Si un usuario quiere agregar 2 «Oranges», «Oranges» aparecerá dos veces en el iterable de entrada. Si el usuario ya tiene el artículo en su carrito, la cantidad en el carrito debe aumentarse en 1. Si el artículo es nuevo en el carrito, debe agregarse con una cantidad de 1.

Crea la función add_items!(<cart>, <items>) que toma un diccionario de carrito y un iterable de artículos para agregar como argumentos. Debe devolver el diccionario del carrito de compras actualizado para el usuario.

julia> additems!(Dict("Banana" => 3, "Apple" => 2, "Orange" => 1),
                 ("Apple", "Apple", "Orange", "Apple", "Banana"))
Dict{String, Int64} with 3 entries:
  "Apple"  => 5
  "Orange" => 2
  "Banana" => 4

julia> additems!(Dict("Banana" => 3, "Apple" => 2, "Orange" => 1),
                 ["Banana", "Orange", "Blueberries", "Banana"])
Dict{String, Int64} with 4 entries:
  "Blueberries" => 1
  "Apple"       => 2
  "Orange"      => 2
  "Banana"      => 5

2. Actualiza la sección de «ideas» de recetas

La app tiene una sección de «ideas» que está llena de recetas terminadas de distintas cocinas. El usuario puede seleccionar cualquiera de estas recetas y hacer que todos sus ingredientes se agreguen automáticamente a su carrito de compras. El gerente del proyecto te ha pedido que crees una forma de editar estas recetas de «ideas», ya que el equipo de contenido cambia constantemente los ingredientes y las cantidades.

Crea la función update_recipes!(<ideas>, <updates>) que toma un diccionario de «ideas» y un diccionario de actualizaciones de recetas como argumentos. La función debe devolver el diccionario de «ideas» actualizado.

julia>update_recipes!(
        Dict("Banana Bread"  => Dict("Banana" => 1, "Apple" => 1, "Walnuts" => 1, "Flour" => 1, "Eggs" => 2, "Butter" => 1),
             "Raspberry Pie" => Dict("Raspberry" => 1, "Orange" => 1, "Pie Crust" => 1, "Cream Custard" => 1)),
        Dict("Banana Bread" => Dict("Banana" => 4,  "Walnuts" => 2, "Flour" => 1, "Butter" => 1, "Milk" => 2, "Eggs" => 3))
    )
Dict{String, Dict{String, Int64}} with 2 entries:
  "Raspberry Pie" => Dict("Cream Custard"=>1, "Raspberry"=>1, "Orange"=>1, "Pie Crust"=>1)
  "Banana Bread"  => Dict("Eggs"=>3, "Flour"=>1, "Milk"=>2, "Butter"=>1, "Walnuts"=>2, "Banana"=>4)

julia> update_recipes!(
    Dict("Banana Bread"    => Dict("Banana" => 1, "Apple" => 1, "Walnuts" => 1, "Flour" => 1, "Eggs" => 2, "Butter" => 1),
         "Raspberry Pie"   => Dict("Raspberry" => 1, "Orange" => 1, "Pie Crust" => 1, "Cream Custard" => 1),
         "Pasta Primavera" => Dict("Eggs" => 1, "Carrots" => 1, "Spinach" => 2, "Tomatoes" => 3, "Parmesan" => 2, "Milk" => 1, "Onion" => 1)),
    Dict("Raspberry Pie"    => Dict("Raspberry" => 3, "Orange" => 1, "Pie Crust" => 1, "Cream Custard" => 1, "Whipped Cream" => 2),
        "Pasta Primavera"   => Dict("Eggs" => 1, "Mixed Veggies" => 2, "Parmesan" => 2, "Milk" => 1, "Spinach" => 1, "Bread Crumbs" => 1),
        "Blueberry Crumble" => Dict("Blueberries" => 2, "Whipped Creme" => 2, "Granola Topping" => 2, "Yogurt" => 3))
    )
Dict{String, Dict{String, Int64}} with 4 entries:
  "Raspberry Pie"     => Dict("Raspberry"=>3, "Orange"=>1, "Pie Crust"=>1, "Cream Custard"=>1, "Whipped Cream"=>2)
  "Pasta Primavera"   => Dict("Eggs"=>1, "Mixed Veggies"=>2, "Parmesan"=>2, "Milk"=>1, "Spinach"=>1, "Bread Crumbs"=>1)
  "Blueberry Crumble" => Dict("Blueberries"=>2, "Whipped Creme"=>2, "Granola Topping"=>2, "Yogurt"=>3)
  "Banana Bread"      => Dict("Banana"=>1, "Apple"=>1, "Walnuts"=>1, "Flour"=>1, "Eggs"=>2, "Butter"=>1)

3. Envía el carrito de compras del usuario a la tienda para surtir el pedido

La app necesita enviar el carrito de un usuario determinado a la tienda para surtir el pedido. Sin embargo, quienes preparan los pedidos en la tienda necesitan saber dónde se puede encontrar cada artículo usando un código de pasillo único. El «carrito de surtido» debe ordenarse según los códigos de pasillo de los artículos para que quienes preparan los pedidos sean más eficientes.

Crea la función send_to_store(<cart>, <aislecodes>) que toma un carrito de compras de usuario y un diccionario que tiene los números de pasillo de la tienda. La función debe devolver un «carrito de surtido» combinado que tenga un par aislecode => quantity para cada artículo que pide el cliente. Los artículos deben aparecer en el orden de sus códigos de pasillo.

julia> cart = Dict("Orange" => 1, "Milk" => 2, "Banana" => 3, "Apple" => 2, "Chocolate" => 2);

julia> aislecodes = Dict("Orange" => 2.4, "Milk" => 3.3, "Banana" => 2.6, "Apple" => 2.2, "Chocolate" => 5.7);

julia> send_to_store(cart, aislecodes)
5-element Vector{Pair{Float64, Int64}}:
 2.2 => 2
 2.4 => 1
 2.6 => 3
 3.3 => 2
 5.7 => 2

4. Actualiza el inventario de la tienda para reflejar lo que ha pedido un usuario

La app no puede simplemente hacer pedidos de clientes indefinidamente. Tarde o temprano, la tienda se va a quedar sin varios productos. Así que el MVP de tu app necesita actualizar el inventario de la tienda cada vez que un usuario envía su pedido a la tienda. De lo contrario, los clientes pedirán productos que en realidad no están disponibles.

Crea la función update_store_inventory!(<inventory>, <cart>) que toma un cart y un inventory. La función debe reducir las cantidades del inventario de la tienda según el número pedido en el carrito y luego devolver un diccionario de los artículos que estén agotados (es decir, los que hayan llegado a 0).

julia> inventory = Dict("Banana" => 15, "Apple" => 12, "Orange" => 1, "Milk" => 4);

julia> cart = Dict("Orange" => 1, "Milk" => 2, "Banana" => 3, "Apple" => 2);

julia> update_store_inventory!(inventory, cart)
Dict{String, Int64} with 1 entry:
  "Orange" => 0

julia> inventory
Dict{String, Int64} with 4 entries:
  "Milk"   => 2
  "Apple"  => 10
  "Orange" => 0
  "Banana" => 12

5. Vuelve a pedir los artículos agotados

Además de actualizar el inventario, tu app puede ayudar a reabastecerlo. Tu MVP debería poder preparar un mini pedido de los artículos que estén agotados después del pedido de un cliente. Esto ayudará a que sea más sencillo generar un pedido grande. Además, a veces hay artículos promocionales por tiempo limitado que no están en la lista de existencias. Si se agotan antes de que termine el período promocional, habrán demostrado ser populares y se pueden agregar a la lista de existencias.

Crea la función reorder!(<outofstock>, <stock>) que toma outofstock y stock. El diccionario stock contiene artículos estándar en existencia y sus cantidades de reorden. El diccionario outofstock es el resultado de update_store_inventory!, es decir, un diccionario de artículos con cantidad cero. Las cantidades de outofstock deben actualizarse para reflejar las de stock y devolverse. Además, cualquier artículo en outofstock que no esté presente en stock debe agregarse a stock con una cantidad predeterminada de 100.

julia> inventory = Dict("Banana" => 15, "Apple" => 12, "Orange" => 1, "Milk" => 4, "Chocolate" => 2);

julia> cart = Dict("Orange" => 1, "Milk" => 2, "Banana" => 3, "Apple" => 2, "Chocolate" => 2);

julia> stock = Dict("Banana" => 150, "Apple" => 120, "Orange" => 120, "Milk" => 45);

julia> outofstock = update_store_inventory!(inventory, cart)
Dict{String, Int64} with 1 entry:
  "Orange"    => 0
  "Chocolate" => 0

julia> reorder!(outofstock, stock)
Dict{String, Int64} with 1 entry:
  "Orange"    => 120
  "Chocolate" => 100

julia> stock 
Dict{String, Int64} with 5 entries:
  "Milk"      => 45
  "Apple"     => 120
  "Chocolate" => 100
  "Orange"    => 120
  "Banana"    => 150
Editar en GitHub El enlace se abre en una ventana o una pestaña nuevas
Julia Exercism

¿Todo listo para empezar Gestión de bocadillos mecha?

Regístrate en Exercism para aprender y dominar Julia con 35 conceptos128 ejercicios y mentoría humana real, todo gratis.