Треки
/
Elm
Elm
/
Вправи
/
Найкращі бомбардири
Найкращі бомбардири

Найкращі бомбардири

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

Вступ

Dict

У Elm Dict - це незмінний словник із нуля або більше пар ключ-значення.

Зі словниками працюють за допомогою функцій та операторів, визначених у модулі Dict.

Анотації типів для словників записують так:

Dict String (List Int) --> a dict with String keys and List Int values
Dict Int String --> a dict with Int keys and String values

Словники можна створювати так:

empty : Dict Int String
empty = Dict.empty

singleValue = Dict.singleton 5 "Value for key 5" --> Dict Int String

twoValues = Dict.fromList [ ( "Alice", 0 ), ( "Bob", 1 ) ] --> Dict String Int

Елементи можна отримати за допомогою get. Оскільки ключ може бути присутнім у словнику, а може й ні, результат буде загорнуто в Maybe.

alice = Dict.fromList [ ( 0, "Alice" ) ]
keyExists = Dict.get 0 alice --> Just "Alice"
keyNotPresent = Dict.get 1 alice --> Nothing

Елементи можна додавати за допомогою insert. Елементи для ключів, які вже є у словнику, замінюються.

alice = Dict.fromList [ ( "Alice", 0 ) ]
aliceAndBob = Dict.insert "Bob" 1 alice  --> Dict.fromList [ ( "Alice", 0 ), ( "Bob", 1 ) ]
aliceAndAlice = Dict.insert "Alice" 1 alice  --> Dict.fromList [ ( "Alice", 1 ) ]

Елементи можна оновлювати за допомогою update. Якщо ключа не існує, функцію оновлення буде викликано з Nothing.

alice = Dict.fromList [ ( 0, "Alice" ) ]
aliceUpperCase = Dict.update 0 (Maybe.map String.toUpper) alice --> Dict.fromList [ ( 0, "ALICE" ) ]
aliceNoCase = Dict.update 0 (\_ -> Nothing) alice --> Dict.empty
bobUpperCase = Dict.update 1 (\_ -> Just "BOB") alice --> Dict.fromList [ ( 0, "Alice" ), ( 1, "BOB" ) ]
bobNoCase = Dict.update 1 (\_ -> Nothing) alice --> Dict.fromList [ ( 0, "Alice" ) ]

Елементи можна видаляти за допомогою remove. Якщо ключа не існує, нічого не змінюється.

alice = Dict.fromList [ ( 0, "Alice" ) ]
stillAlice = Dict.remove 1 --> ( 0, "Alice" )
empty = Dict.remove 0 alice --> Dict.empty

Масив пар ключ-значення можна перетворити на словник за допомогою fromList.

alice = Dict.fromList [ ( 0, "Bob" ), ( 0, "Alice" ) ]
--> True Dict.fromList [ ( 0, "Alice" ) ]

Елементи можна перетворити на масив за допомогою toList. Масив упорядковано за ключами.

aliceAndBob = Dict.fromList [ ( 1, "Alice" ), ( 0, "Bob" ) ]
bobAndAlice = Dict.toList aliceAndBob
--> [ ( 0, "Bob" ), ( 1, "Alice" ) ]

Кілька елементів можна видалити за допомогою filter.

aliceAndBob = Dict.fromList [ ( "Alice", 1 ), ( "Bob", 0 ) ]
bob = Dict.filter (\name count -> name == "Bob") aliceAndBob --> Dict.fromList [ ( "Bob", 0 ) ]

Елементи можна перетворити за допомогою map.

alice = Dict.fromList [ ( "Alice", 0 ) ]
empty = Dict.map (\player count -> count + 1) alice --> Dict.fromList [ ( "Alice", 1 ) ]

Словники можна поєднувати й перетворювати за допомогою merge.

aliceAndBob = Dict.fromList [ ( "Alice", 1 ), ( "Bob", 1 ) ]
bobAndCedd = Dict.fromList [ ( "Bob", 1 ), ( "Cedd", 1 ) ]
firstDictCountsDouble = Dict.merge
        -- when only in aliceAndBob
        (\name count mergedCounts -> Dict.insert name (2 * count) mergedCounts)
        -- when in aliceAndBob and bobAndCedd
        (\name aliceAndBobCount bobAndCeddCount mergedCounts -> Dict.insert name (2 * aliceAndBobCount + bobAndCeddCount) mergedCounts)
        -- when only in bobAndCedd
        (\name count mergedCounts -> Dict.insert name count mergedCounts)
        -- the two dicts to merge
        aliceAndBob
        bobAndCedd
        -- the initial state of the merge
        Dict.empty
--> Dict.fromList [ ( "Alice", 2 ), ( "Bob", 3 ), ( "Cedd", 1 ) ]

Будь-яка функція чи оператор, які нібито змінюють словник (наприклад, додають елемент), насправді повертають новий словник. Продуктивність зазвичай не є проблемою, адже реалізація запобігає зайвим виділенням памʼяті та копіюванням.

В Elm зазвичай краще використовувати абстракції вищого рівня, як-от Dict.map, Dict.filter і Dict.merge, замість абстракцій нижчого рівня, як-от Dict.get і Dict.remove, хоча це, звісно, залежить від контексту.

Вказівки

Ваше завдання - взяти список бомбардирів гри та порахувати, скільки голів забив кожен гравець.

PlayerName - це псевдонім типу для String, щоб код було легше читати та щоб відрізняти це використання String від інших використань String.

1. Підсумувати бомбардирів

Спершу реалізуйте updateGoalCountForPlayer, щоб ініціалізувати або збільшити лічильник голів гравця. Потім реалізуйте функцію aggregateScorers, щоб порахувати, скільки голів забив кожен гравець, використовуючи updateGoalCountForPlayer. Ця функція приймає List PlayerName (імена гравців, які забили голи; імена можуть повторюватися) і повертає Dict PlayerName Int з усіма гравцями зі списку та кількістю забитих ними голів.

aggregateScorers [ "Betty", "Cedd", "Betty" ]
--> Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 1 ) ]

2. Прибрати незначущих гравців

Реалізуйте функцію removeInsignificantPlayers, щоб відфільтрувати гравців, які забили менше голів, ніж поріг.

removeInsignificantPlayers 2 (Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 1 ) ] )
--> Dict.fromList [ ( "Betty", 2 ) ]

3. Скинути лічильник голів гравця

Реалізуйте функцію resetPlayerGoalCount, щоб скинути кількість забитих гравцем голів до нуля.

resetPlayerGoalCount "Cedd" (Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 1 ) ] )
--> Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 0 ) ]

4. Відформатувати кількість голів одного гравця

Реалізуйте функцію formatPlayer, щоб відформатувати кількість голів одного гравця як рядок тексту (англ. string). Якщо гравця немає в словнику, вважайте, що він забив нуль голів.

formatPlayer "Betty" (Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 1 ) ] )
--> "Betty: 2"

5. Відформатувати кількість голів усіх гравців

Реалізуйте функцію formatPlayers, щоб відформатувати кількість голів усіх гравців як рядок тексту. Гравців потрібно впорядкувати за іменем.

formatPlayers (Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 1 ) ] )
--> "Betty: 2, Cedd: 1"

6. Обʼєднати ігри

Реалізуйте функцію combineGames, яка рахує загальну кількість голів, забитих кожним гравцем в обох іграх.

combine Games
  (Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 1 ) ] )
  (Dict.fromList [ ( "Betty", 2 ), ( "Mario", 3 ) ] )
--> Dict.fromList [ ( "Betty", 4 ), ( "Cedd", 1 ), ( "Mario", 3 ) ]
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
Elm Exercism

Час розпочати Найкращі бомбардири?

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