Enum - це дуже корисний модуль, який надає набір алгоритмів для роботи з перелічуваними. Він уміє сортувати, фільтрувати, групувати, рахувати, шукати, знаходити мінімальні й максимальні значення та багато іншого.
Загалом перелічуване - це будь-які дані, які можна перебрати, тобто певна сукупність. В Elixir перелічуваним є будь-який тип даних, який реалізує протокол Enumerable. Найпоширеніші з них - це масиви і словники.
Багато функцій Enum приймають функцію як аргумент.
Enum.all?([1, 2, 3, 4, 5], fn x -> x > 3 end)
# => false
Найпоширеніші функції Enum - це map і reduce.
map/2Enum.map/2 дає змогу замінити кожен елемент у перелічуваному на інший елемент. Другий аргумент Enum.map/2 - це функція, яка приймає початковий елемент і повертає його заміну.
reduce/3Enum.reduce/3 дає змогу звести все перелічуване до одного значення. Для цього використовується спеціальна змінна, яку називають акумулятором. Акумулятор зберігає проміжний стан зведення між ітераціями.
Другий аргумент Enum.reduce/3 - це початкове значення акумулятора. Третій аргумент - це функція, яка приймає елемент та акумулятор і повертає нове значення акумулятора.
Коли ми використовуємо словники з функціями Enum, словник автоматично перетворюється на масив із двох кортежів {key, value}.
Щоб перетворити його назад у словник, використаймо Enum.into/2. Enum.into/2 - це функція, яка перетворює перелічуване в колекцію, тобто в будь-яку структуру даних, що реалізує протокол Collectable. Її можна вважати протилежністю Enum.reduce/3.
У Enum також є Enum.into/3. Enum.into/3 - це варіант Enum.into/2, який приймає функцію перетворення, що застосовується під час перетворення перелічуваного в колекцію.
Замість того щоб використовувати Enum.into/3, або Enum.map/2 разом із Enum.into/2, для застосування перетворення (відображення) до словника, можна також скористатися спеціальною функцією Map.new/2. Вона працює точно так само, як Enum.into/3: приймає перелічуване і функцію перетворення, але завжди повертає новий словник, а не дає нам обрати колекцію.
Ми керуємо онлайн-бутиком модного одягу. Наближається наш великий щорічний розпродаж, тож потрібно перевірити інвентар, щоб переконатися, що ми готові.
Один товар в інвентарі представлено мапою, а весь інвентар - це список таких мап.
%{
name: "White Shirt",
price: 40,
quantity_by_size: %{s: 3, m: 7, l: 8, xl: 4}
}
Реалізуйте функцію sort_by_price/1. Вона приймає інвентар і повертає його, відсортований за ціною товару за зростанням.
BoutiqueInventory.sort_by_price([
%{price: 65, name: "Maxi Brown Dress", quantity_by_size: %{}},
%{price: 50, name: "Red Short Skirt", quantity_by_size: %{}},
%{price: 50, name: "Black Short Skirt", quantity_by_size: %{}},
%{price: 20, name: "Bamboo Socks Cats", quantity_by_size: %{}}
])
# => [
# %{price: 20, name: "Bamboo Socks Cats", quantity_by_size: %{}},
# %{price: 50, name: "Red Short Skirt", quantity_by_size: %{}},
# %{price: 50, name: "Black Short Skirt", quantity_by_size: %{}},
# %{price: 65, name: "Maxi Brown Dress", price: 65, quantity_by_size: %{}}
# ]
Після сортування інвентарю за ціною ми помітили, що, мабуть, припустилися помилки, коли проводили інвентаризацію, і забули вказати ціни для кількох товарів.
Реалізуйте функцію with_missing_price/1. Вона приймає інвентар і повертає список товарів, у яких немає ціни.
BoutiqueInventory.with_missing_price([
%{price: 40, name: "Black T-shirt", quantity_by_size: %{}},
%{price: nil, name: "Denim Pants", quantity_by_size: %{}},
%{price: nil, name: "Denim Skirt", quantity_by_size: %{}},
%{price: 40, name: "Orange T-shirt", quantity_by_size: %{}}
])
# => [
# %{price: nil, name: "Denim Pants", quantity_by_size: %{}},
# %{price: nil, name: "Denim Skirt", quantity_by_size: %{}}
# ]
Ми помітили, що в назвах деяких товарів є слово, яке ми більше не хочемо використовувати. Тепер потрібно оновити всі назви товарів із цим словом.
Реалізуйте функцію update_names/3. Вона приймає інвентар, старе слово, яке потрібно прибрати, і нове слово, яке потрібно використати замість нього. Вона повертає список товарів з оновленими назвами.
BoutiqueInventory.update_names(
[
%{price: 40, name: "Black T-shirt", quantity_by_size: %{}},
%{price: 70, name: "Denim Pants", quantity_by_size: %{}},
%{price: 65, name: "Denim Skirt", quantity_by_size: %{}},
%{price: 40, name: "Orange T-shirt", quantity_by_size: %{}}
],
"T-shirt",
"Tee"
)
# => [
# %{price: 40, name: "Black Tee", quantity_by_size: %{}},
# %{price: 70, name: "Denim Pants", quantity_by_size: %{}},
# %{price: 65, name: "Denim Skirt", quantity_by_size: %{}},
# %{price: 40, name: "Orange Tee", quantity_by_size: %{}}
# ]
Деякі товари продавалися особливо добре, тож ми замовили більше, у всіх розмірах.
Реалізуйте функцію increase_quantity/2. Вона приймає один товар і число n та повертає цей товар, у якому кількість для кожного розміру збільшено на n.
BoutiqueInventory.increase_quantity(
%{
name: "Polka Dot Skirt",
price: 68,
quantity_by_size: %{s: 3, m: 5, l: 3, xl: 4}
},
6
)
# => %{
# name: "Polka Dot Skirt",
# price: 68,
# quantity_by_size: %{l: 9, m: 11, s: 9, xl: 10}
# }
Щоб знати, скільки місця потрібно на складі, потрібно знати, скільки всього одиниць кожного товару ми маємо.
Реалізуйте функцію total_quantity/1. Вона приймає один товар і повертає, скільки всього одиниць цього товару ми маємо в усіх розмірах разом.
BoutiqueInventory.total_quantity(%{
name: "Red Shirt",
price: 62,
quantity_by_size: %{s: 3, m: 6, l: 5, xl: 2}
})
# => 16
Зареєструйтеся на Exercism, щоб вивчати й опановувати Elixir, а також 58 концепцій168 вправ та справжнє наставництво від людей, і все це безкоштовно.