O conceito Pares e Dicionários abordou os fundamentos do tipo dicionário de Julia.
Como os Dicts são um tipo de coleção importante e muito usado, também existem muitas funções para manipulá-los.
A forma mais simples de recuperar uma entrada é pela chave (como em muitas linguagens).
No entanto, pedir uma chave que não existe gera um 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
Poderíamos testar a chave antes de tentar recuperá-la (com algo como haskey(d, 4)), mas pode ser útil simplesmente obter um valor padrão para chaves ausentes.
Para isso, temos a função get() e sua variante que altera o dicionário, get!().
A diferença entre elas é se uma chave "ausente" é adicionada ao 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'
Vimos no conceito anterior que delete!() remove uma entrada pela chave.
Isso pode ser combinado com a recuperação do valor, usando a função 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'
Iterar sobre um Dict produz, por padrão, pares key => value.
Os componentes são acessíveis com a nomenclatura usual .first e .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')
Muitas vezes, queremos usar apenas as chaves ou apenas os valores, o que é 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)
Combinar dois Dicts pode ser útil, mas precisamos deixar claro o que pretendemos fazer com chaves que aparecem em mais de uma entrada.
As funções merge() e merge!() combinam um número arbitrário de Dicts fornecidos, da esquerda para a direita.
Os valores das chaves já existentes são simplesmente sobrescritos, então o Dict mais à direita "vence".
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)
As funções mergewith() e mergewith!() permitem passar uma função como primeiro argumento, para definir como chaves repetidas devem ser mescladas.
A adição é um exemplo simples.
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"
Repare que as funções mergewith são um bom exemplo de funções de ordem superior em ação.
A Mecha Munch™, uma empresa de automação de compras de supermercado, acaba de contratar você para trabalhar no aplicativo de pedidos deles. Sua equipe ficou encarregada de construir um MVP (produto mínimo viável) que gerencia todas as atividades básicas do carrinho de compras, permitindo que os usuários adicionem, removam e ordenem seus pedidos de supermercado. Felizmente, outra equipe cuida de todas as funções de pagamento e finalização da compra!
O MVP deve permitir que o usuário adicione itens ao carrinho de compras. Pode ser um único item ou vários itens de uma vez. Como este é um MVP, a quantidade de itens é indicada por repetições. Se um usuário quiser adicionar 2 Oranges, 'Oranges' aparecerá duas vezes no iterável de entrada. Se o usuário já tiver o item no carrinho, a quantidade no carrinho deve ser aumentada em 1. Se o item for novo no carrinho, ele deve ser adicionado com quantidade 1.
Crie a função add_items!(<cart>, <items>) que recebe como argumentos um dicionário de carrinho e um iterável de itens a adicionar.
Ela deve retornar o dicionário do carrinho de compras atualizado para o usuário.
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
O aplicativo tem uma seção de "ideias" preenchida com receitas prontas de diversas cozinhas. O usuário pode selecionar qualquer uma dessas receitas e ter todos os seus ingredientes adicionados automaticamente ao carrinho de compras. O gerente de projeto pediu que você criasse uma forma de editar essas receitas de "ideias", já que a equipe de conteúdo vive mudando ingredientes e quantidades.
Crie a função update_recipes!(<ideas>, <updates>) que recebe como argumentos um dicionário de "ideias" e um dicionário de atualizações de receitas.
A função deve retornar o dicionário de "ideias" atualizado.
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)
O aplicativo precisa enviar o carrinho de um determinado usuário para a loja para separação. No entanto, os separadores da loja precisam saber onde o item pode ser encontrado, usando um código de corredor único. O "carrinho de separação" precisa ser ordenado pela ordem dos códigos de corredor dos itens, para ajudar os separadores a serem mais eficientes.
Crie a função send_to_store(<cart>, <aislecodes>) que recebe um carrinho de compras do usuário e um dicionário com os números de corredor da loja.
A função deve retornar um "carrinho de separação" combinado, com um par aislecode => quantity para cada item que o cliente está pedindo.
Os itens devem aparecer na ordem dos seus códigos de corredor.
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
O aplicativo não pode simplesmente fazer pedidos de clientes sem parar. Em algum momento, a loja vai ficar sem vários produtos. Por isso, o MVP do seu aplicativo precisa atualizar o estoque da loja toda vez que um usuário enviar o pedido para a loja. Caso contrário, os clientes vão pedir produtos que não estão realmente disponíveis.
Crie a função update_store_inventory!(<inventory>, <cart>) que recebe um cart e um inventory.
A função deve reduzir as quantidades do estoque da loja pelo número "pedido" no "cart" e então retornar um dicionário com os itens que estão fora de estoque (ou seja, que chegaram 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
Além de atualizar o estoque, o seu aplicativo pode ajudar a repô-lo. O seu MVP deve ser capaz de preparar um mini-pedido de qualquer item que esteja fora de estoque após o pedido de um cliente. Isso vai ajudar a tornar mais simples o disparo de um pedido maior. Além disso, às vezes há itens promocionais por tempo limitado que não estão na lista de estoque. Se eles esgotarem antes do fim do período promocional, é sinal de que fizeram sucesso e podem ser adicionados à lista de estoque.
Crie a função reorder!(<outofstock>, <stock>) que recebe outofstock e stock.
O dicionário stock contém itens de estoque padrão e suas quantidades de reposição.
O dicionário outofstock é o resultado de update_store_inventory!, ou seja, um dicionário de itens com quantidade zero.
As quantidades em outofstock devem ser atualizadas para refletir as de stock e retornadas.
Além disso, qualquer item em outofstock que não esteja presente em stock deve ser adicionado a stock com uma quantidade padrão 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
Crie sua conta no Exercism para aprender e dominar Julia com 35 conceitos128 exercícios e mentoria humana de verdade, tudo de graça.