Треки
/
Julia
Julia
/
Вправи
/
Пропозиції бутіка
Пропозиції бутіка

Пропозиції бутіка

Навчальна вправа

Вступ

Кожен, хто працював із Python, майже напевно користувався включеннями списків, які є невіддільною частиною синтаксису Python від найперших версій.

Щось настільки зручне поступово потрапляє і в інші мови, зокрема в Julia.

Для програмістів Julia включення радше можливість, ніж необхідність, адже зазвичай є альтернативи (broadcasting, функції вищого порядку тощо).

Однак включення часто дає простий, читабельний і продуктивний спосіб побудувати масив. Зрештою, це справа особистого смаку й того, як ми ставимося до Python порівняно з функціональними мовами.

Синтаксис здебільшого прямо запозичено з Python, але з розширеннями для багатовимірних масивів.

Одна змінна

Дуже в дусі Python, включно з необовʼязковою умовою if.

julia> [x^2 for x in 1:3]
3-element Vector{Int64}:
 1
 4
 9
julia> [x^2 for x in 1:3 if isodd(x^2)]
2-element Vector{Int64}:
 1
 9

Форма вихідних даних залежить від деталей включення: у простих випадках вона зазвичай така сама, як у вхідної колекції, але умова if сплющує її до Vector.

julia> m
2×3 Matrix{Int64}:
 1  2  3
 4  5  6
julia> [x^2 for x in m]
2×3 Matrix{Int64}:
  1   4   9
 16  25  36
julia> [x^2 for x in m if isodd(x^2)] 
3-element Vector{Int64}:
  1
 25
  9

Кілька змінних, вихідні дані Vector

Як і в Python, ми можемо мати кілька секцій for з різними змінними та однаковими або різними вхідними колекціями.

julia> [x * y for x in 1:3 for y in 4:6]
9-element Vector{Int64}:
  4
  5
  6
  8
 10
 12
 12
 15
 18
julia> [x * y for x in 1:3 for y in 4:6 if isodd(x * y)]
2-element Vector{Int64}:
  5
 15

Це еквівалентно вкладеним циклам. Вихідні дані одновимірні, навіть якщо на вході матриця.

julia> m
2×3 Matrix{Int64}:
 1  2  3
 4  5  6
julia> [x*y for x in m for y in m]
36-element Vector{Int64}:
  1
  4
  2
  5
(truncated output...)

Кілька змінних, багатовимірні вихідні дані

У попередньому розділі йшлося про кілька секцій for, розділених лише пробілами.

У цьому розділі є лише одна секція for, а змінні розділені комами.

julia> [(x, y) for x in 1:3, y in 4:6]
3×3 Matrix{Tuple{Int64, Int64}}:
 (1, 4)  (1, 5)  (1, 6)
 (2, 4)  (2, 5)  (2, 6)
 (3, 4)  (3, 5)  (3, 6)

Кожна змінна у включенні створює новий вимір у вихідних даних, з елементом для кожної можливої комбінації змінних.

У наведеному вище прикладі x зростає вниз по рядках, а y - упоперек стовпців. Вищі виміри теж можливі, зі звичними застереженнями щодо читабельності вихідних даних.

Генераторні вирази

У попередніх розділах ішлося про вихідні дані у вигляді масиву, де включення розміщене всередині квадратних дужок [ ... ].

Коли квадратні дужки замінити на круглі ( ... ), відбувається дещо інше: ми отримуємо generator expression, тобто ліниво обчислюваний ітератор, який може видавати наступне значення на вимогу.

julia> g = ((x, y) for x in 1:3, y in 4:6)
Base.Generator{Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}, var"#9#10"}(var"#9#10"(), Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}((1:3, 4:6)))
# Indexing fails with a generator, the entries don't exist yet
julia> g[1, 2]
ERROR: MethodError: no method matching getindex(::Base.Generator{Base.Iterators.ProductIterator{Tuple{UnitRange{…}, UnitRange{…}}}, var"#9#10"}, ::Int64, ::Int64)
# conversion to array
julia> collect(g)
3×3 Matrix{Tuple{Int64, Int64}}:
 (1, 4)  (1, 5)  (1, 6)
 (2, 4)  (2, 5)  (2, 6)
 (3, 4)  (3, 5)  (3, 6)
# generators are mainly designed for iteration
julia> [i * j for (i, j) in g]
3×3 Matrix{Int64}:
  4   5   6
  8  10  12
 12  15  18

Коли результат включення одразу використовується для подальшої обробки, генератор може бути ощадливим до памʼяті, уникаючи потреби зберігати великий проміжний масив.

Генератору, використаному як аргумент функції, не потрібні додаткові дужки.

# inefficient
julia> v = [x^2 for x in 1:1e6];
julia> sum(v)
3.333338333335e17
# better - use a generator
julia> sum(x^2 for x in 1:1e6)
3.3333383333312755e17

Синтаксис генератора ідентичний до включень, окрім навколишніх дужок.

Генератори також зручні в конструкторах словників.

julia> Dict(x => x^2 for x in 1:5)
Dict{Int64, Int64} with 5 entries:
  5 => 25
  4 => 16
  2 => 4
  3 => 9
  1 => 1

Вказівки

Ми працюємо в інтернет-магазині модного одягу. У нас виникає ідея нової можливості сайту: пропонувати користувачам комплекти одягу. Нас цікавлять можливі комплекти, їхні ціни та усунення несумісних варіантів.

Note

Хоча наведені нижче задачі можна розвʼязати різними способами, усі їх можна розвʼязати за допомогою генератора.

1. Створити елемент одягу

Реалізуйте clothingitem(), яка приймає два Tuple: один із categories, а другий із відповідними qualities. Функція повинна повернути Dict, де ключами є categories, а значеннями - qualities.

julia> categories = ("item_name", "price", "color", "base_color");

julia> qualities = ("Descriptive Name", 99.00, "Ochre Red", "red");

julia> clothingitem(categories, qualities)
Dict{String, Any} with 4 entries:
  "price"      => 99.0
  "item_name"  => "Descriptive Name"
  "base_color" => "red"
  "color"      => "Ochre Red"

Функція повинна впоратися з будь-якою кількістю categories.

2. Запропонувати комбінації

Реалізуйте get_combinations(), яка приймає Tuple верхів і Tuple низів. Функція повинна повернути cartesian product цих кортежів як двовимірний масив (тобто Matrix). Кожен елемент - це комбінація (top, bottom) у вигляді Tuple. Верх змінюється від рядка до рядка, а низ - від стовпця до стовпця.

julia> tops = (
        Dict("item_name" => "Dress shirt"),
        Dict("item_name" => "Casual shirt")
        );

julia> bottoms = (
        Dict("item_name" => "Jeans"),
        Dict("item_name" => "Dress trousers")
       );

julia> get_combinations(tops, bottoms)
2×2 Matrix{Tuple{Dict{String, String}, Dict{String, String}}}:
 (Dict("item_name"=>"Dress shirt"), Dict("item_name"=>"Jeans"))   (Dict("item_name"=>"Dress shirt"), Dict("item_name"=>"Dress trousers"))
 (Dict("item_name"=>"Casual shirt"), Dict("item_name"=>"Jeans"))  (Dict("item_name"=>"Casual shirt"), Dict("item_name"=>"Dress trousers"))

3. Підсумувати ціни комплектів

Кожен елемент одягу має повʼязане з ним поле price, тож корисно мати змогу порівнювати повну ціну комплектів. Реалізуйте get_prices(), яка приймає масив комбінацій одягу. Функція повинна повернути масив такої самої форми з цінами комплектів на відповідних позиціях.

julia> tops = (
        Dict("item_name" => "Dress shirt", "base_color" => "blue", "price" => 35),
        Dict("item_name" => "Casual shirt", "base_color" => "black", "price" => 20)
       );

julia> bottoms = (
        Dict("item_name" => "Jeans", "base_color" => "blue", "price" => 30),
        Dict("item_name" => "Dress trousers", "base_color" => "black", "price" => 75)
       );

julia> combomatrix = get_combinations(tops, bottoms);

julia> get_prices(combomatrix)
2×2 Matrix{Int}::
 65  110
 50   95

julia> filteredmatrix = filter_clashing(combomatrix)
1-element Vector{Tuple{Dict{String, Any}, Dict{String, Any}}}:
 (Dict("price" => 20, "item_name" => "Casual shirt", "base_color" => "black"), Dict("price" => 30, "item_name" => "Jeans", "base_color" => "blue"))

julia> get_prices(filteredmatrix)
1-element Vector{Int}:
 50

4. Відфільтрувати несумісні комплекти

Кожен елемент одягу має поле base_color. Скористайтеся цим полем, щоб прибрати всі комбінації, у яких верх і низ мають однаковий базовий колір. Реалізуйте filter_clashing(), яка приймає масив комбінацій одягу. Поверніть одновимірний масив (тобто Vector) відповідних комбінацій.

julia> tops = (
        Dict("item_name" => "Dress shirt", "base_color" => "blue", "price" => 35),
        Dict("item_name" => "Casual shirt", "base_color" => "black", "price" => 20)
       );

julia> bottoms = (
        Dict("item_name" => "Jeans", "base_color" => "blue", "price" => 30),
        Dict("item_name" => "Dress trousers", "base_color" => "black", "price" => 75)
       );

julia> combos = get_combinations(tops, bottoms);

julia> filter_clashing(combos)
1-element Vector{Tuple{Dict{String, Any}, Dict{String, Any}}}:
 (Dict("price" => 20, "item_name" => "Casual shirt", "base_color" => "black"), Dict("price" => 30, "item_name" => "Jeans", "base_color" => "blue"))
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
Julia Exercism

Час розпочати Пропозиції бутіка?

Зареєструйтеся на Exercism, щоб вивчати й опановувати Julia, а також 35 концепцій128 вправ та справжнє наставництво від людей, і все це безкоштовно.