У концепті «Пари та словники» ми розглянули основи словникового типу в Julia.
Оскільки Dict є важливим і часто використовуваним типом колекції, для роботи з ним існує також багато функцій.
Найпростіше отримати запис можна за ключем (як і в багатьох мовах).
Однак звернення до неіснуючого ключа призводить до помилки 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
Ми могли б перевірити наявність ключа, перш ніж намагатися його отримати (наприклад, за допомогою haskey(d, 4)), але буває зручно просто отримати типове значення для відсутніх ключів.
Для цього є функція get() та її варіант get!(), який змінює словник.
Вони відрізняються тим, чи додається «відсутній» ключ до 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'
У попередньому концепті ми бачили, що delete!() видаляє запис за ключем.
Це можна поєднати з отриманням значення, скориставшись функцією 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'
Коли ми перебираємо Dict, типово отримуємо пари key => value.
До складників можна дістатися за звичними назвами .first і .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')
Часто нам потрібні лише ключі або лише значення, і це легко.
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)
Поєднувати два Dict буває корисно, але варто чітко визначити, що робити з ключами, які присутні в кількох вхідних словниках.
Функції merge() і merge!() поєднують довільну кількість переданих Dict зліва направо.
Значення наявних ключів просто перезаписуються, тож найправіший Dict «перемагає».
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)
Функції mergewith() і mergewith!() дозволяють передати функцію першим аргументом, щоб визначити, як поєднувати повторювані ключі.
Найпростіший приклад - додавання.
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"
Зауважмо, що функції mergewith є гарним прикладом функцій вищого порядку в дії.
Mecha Munch™, компанія з автоматизації закупівель продуктів, щойно найняла нас працювати над своїм застосунком для замовлень. Перед нашою командою стоїть завдання створити MVP (мінімально життєздатний продукт), який керує всіма базовими операціями з кошиком для покупок: дозволяє користувачам додавати, видаляти та сортувати свої замовлення. На щастя, усі грошові операції та оформлення замовлень узяла на себе інша команда!
MVP має дозволяти користувачу додавати товари до свого кошика для покупок. Це може бути один товар або кілька товарів одразу. Оскільки це MVP, кількість товару позначається повтореннями. Якщо користувач хоче додати 2 апельсини, «Oranges» зʼявиться у вхідній послідовності, яку можна перебрати, двічі. Якщо товар уже є в кошику користувача, його кількість у кошику слід збільшити на 1. Якщо товар новий для кошика, його слід додати з кількістю 1.
Створіть функцію add_items!(<cart>, <items>), яка приймає словник кошика та послідовність товарів для додавання як аргументи.
Вона має повернути оновлений словник кошика для покупок користувача.
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
У застосунку є розділ «ідеї», наповнений готовими рецептами різних кухонь. Користувач може вибрати будь-який із цих рецептів, і всі його інгредієнти автоматично додадуться до кошика для покупок. Керівник проєкту попросив створити спосіб редагувати ці рецепти з розділу «ідеї», адже команда контенту постійно змінює інгредієнти та їхні кількості.
Створіть функцію update_recipes!(<ideas>, <updates>), яка приймає словник «ідеї» та словник оновлень рецептів як аргументи.
Функція має повернути оновлений словник «ідеї».
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)
Застосунок має надіслати кошик користувача до магазину для виконання замовлення. Однак працівникам магазину потрібно знати, де знайти товар, за унікальним кодом проходу. «Кошик для виконання» потрібно відсортувати за кодами проходів товарів, щоб працівники магазину працювали ефективніше.
Створіть функцію send_to_store(<cart>, <aislecodes>), яка приймає кошик користувача та словник із номерами проходів магазину.
Функція має повернути обʼєднаний «кошик для виконання», що містить пару aislecode => quantity для кожного товару, який замовляє покупець.
Товари мають бути впорядковані за своїми кодами проходів.
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
Застосунок не може безкінечно приймати замовлення покупців. Зрештою в магазині закінчаться різні товари. Тож MVP нашого застосунку має оновлювати запаси магазину щоразу, коли користувач надсилає своє замовлення до магазину. Інакше покупці замовлятимуть товари, яких насправді немає в наявності.
Створіть функцію update_store_inventory!(<inventory>, <cart>), яка приймає cart та inventory.
Функція має зменшити запаси магазину на кількість, «замовлену» в cart, а потім повернути словник товарів, яких немає в наявності (тобто тих, кількість яких сягнула 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
Окрім оновлення запасів, застосунок може допомогти з їх поповненням. MVP має вміти готувати мінізамовлення на будь-які товари, які закінчилися після замовлення покупця. Це спростить запуск великого замовлення. До того ж іноді є акційні товари з обмеженим терміном дії, яких немає в списку запасів. Якщо вони розпродалися до завершення акції, це означає, що вони популярні, і їх можна додати до списку запасів.
Створіть функцію reorder!(<outofstock>, <stock>), яка приймає outofstock та stock.
Словник stock містить стандартні товари в запасі та кількості для їх повторного замовлення.
Словник outofstock є результатом update_store_inventory!, а саме словником товарів із нульовою кількістю.
Кількості в outofstock слід оновити відповідно до stock і повернути.
Також будь-які товари з outofstock, яких немає в stock, слід додати до stock з типовою кількістю 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
Зареєструйтеся на Exercism, щоб вивчати й опановувати Julia, а також 35 концепцій128 вправ та справжнє наставництво від людей, і все це безкоштовно.