Треки
/
jq
jq
/
Вправи
/
Табло рекордів
Табло рекордів

Табло рекордів

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

Вступ

Обʼєкти

Якщо скористатися термінологією з інших мов, JSON-обʼєкт - це «хеш», «мапа» або «словник».

JSON визначає обʼєкт так:

Обʼєкт - це невпорядкована множина пар імʼя/значення. Обʼєкт починається з { лівої фігурної дужки й закінчується } правою фігурною дужкою. Після кожного імені йде : двокрапка, а пари імʼя/значення розділяються , комою.

Імʼя має бути рядком тексту (англ. string). Інше слово для імені - ключ.

Значення може бути будь-якого типу JSON. Різні значення в одному обʼєкті можуть мати різні типи, як у цьому прикладі.

{
  "name": "Jane",
  "age": 42,
  "pets": ["cat", "fish"],
  "address": {"street": "123 Main St", "city": "Springfield"}
}

Зауважмо, що після останньої пари ключ-значення не повинно стояти коми.

Створення обʼєктів

Щоб зібрати пари імʼя/значення, використовуймо фігурні дужки. Хоча імена мають бути рядками тексту, їх не обовʼязково брати в лапки, якщо імена схожі на ідентифікатори (складаються з буквено-цифрових символів і символу підкреслення та не починаються з цифри).

{name: "Jane", age: 42}

Цілком припустимо використовувати ключі, що не схожі на ідентифікатори. Просто берімо їх у лапки.

{"first name": "Jane", "last name": "Lopez", age: 42}

Якщо імʼя є результатом виразу, то вираз має бути в дужках.

$ echo "Jane" | jq -Rc '{.: 42}'
# verbose error message ...

$ echo "Jane" | jq -Rc '{(.): 42}'
{"Jane":42}

Індексація

Значення з обʼєкта дістають за допомогою точкової нотації.

{name: "Jane", age: 42} | .age    # => 42

Якщо до ключа не вдається звернутися як до ідентифікатора, скористаймося нотацією з квадратними дужками.

"name" as $key | {name: "Jane", age: 42} | .$key    # => error
"name" as $key | {name: "Jane", age: 42} | .[$key]  # => "Jane"

Додавання та зміна пар ключ-значення

Щоб додати нову пару ключ-значення до масиву або оновити значення наявного ключа, використовуймо оператор присвоєння =, де з лівого боку стоїть вираз з індексом.

{name: "Jane", age: 42} | .sport = "tennis" | .age = 21
# => {
#      "name": "Jane",
#      "age": 21,
#      "sport": "tennis"
#    }

Оператор + обʼєднує обʼєкти.

{Richard: 54} + {Jane: 42}
# => {
#      "Richard": 54,
#      "Jane": 42
#    }

Видалення ключа

Щоб видалити ключ, скористаймося функцією del. Вона повертає оновлений обʼєкт.

{name: "Jane", age: 42} | del(.age)   # => {"name": "Jane"}

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

{name: "Jane", age: 42} | del(name)        # error: name/0 is not defined
{name: "Jane", age: 42} | del("name")      # error: Invalid path expression with result "name"
{name: "Jane", age: 42} | del(.name)       # OK
{name: "Jane", age: 42} | del(.["name"])   # OK

Перевірка належності

  • Щоб перевірити, чи містить обʼєкт ключ, скористаймося функцією has.

    {name: "Jane", age: 42} as $example
    |
      ($example | has("name")),    # => true
      ($example | has("sport"))    # => false
    
  • Щоб перевірити, чи є ключ в обʼєкті, скористаймося in.

    {name: "Jane", age: 42} as $example
    |
      ("name"  | in($example)),    # => true
      ("sport" | in($example))     # => false
    

Перелік усіх ключів

Щоб вивести список усіх ключів, скористаймося функцією keys.

{name: "Jane", age: 42} | keys   # => ["age", "name"]

Зауважмо, що keys сортує ключі. Щоб отримати ключі в початковому порядку, скористаймося keys_unsorted.

Немає рівнозначної функції, щоб перелічити всі значення. Утім, фільтр .[] виводить значення обʼєкта як потік, і цей потік можна зібрати конструктором масиву [...].

[{first: "Jane", last: "Lopez", status: "awesome!"} | .[]]
# => ["Jane", "Lopez", "awesome!"]

Перебирання

  • Функція map_values(filter) застосовує фільтр до кожного значення в обʼєкті.

    {first: "Jane", last: "Lopez", status: "awesome!"}
    | map_values(ascii_upcase)
    # => {"first": "JANE", "last": "LOPEZ", "status": "AWESOME!"}
    
  • Щоб перебрати обʼєкт, спершу треба перетворити його на масив обʼєктів ключ-значення. Саме це робить функція to_entries.

    {name: "Jane", age: 42} | to_entries'
    # => [
    #      {
    #        "key": "name",
    #        "value": "Jane"
    #      },
    #      {
    #        "key": "age",
    #        "value": 42
    #      }
    #    ]
    

    Тепер ми можемо скористатися функціями ітерації масивів, як-от map.

  • Функція from_entries виконує зворотну дію: перетворює масив обʼєктів ключ-значення на обʼєкт.

    [
      {"key":"name", "value":"Jane"},
      {"key":"age", "value":42}
    ] | from_entries                  # =>{"name": "Jane", "age": 42}
    
  • Щоб застосувати фільтр до кожної пари ключ-значення в обʼєкті, скористаймося функцією with_entries(filter).

    Наприклад, маючи обʼєкт, який зіставляє імʼя з віком, можна поміняти місцями ключі та значення так.

    {"Jane": 42, "Richard": 54}
    | with_entries({key: (.value | tostring), value: .key})
    

    виводить

    {
      "42": "Jane",
      "54": "Richard"
    }
    

    with_entries(filter) - це те саме, що

    to_entries | map(filter) | from_entries
    

Вказівки

У цій вправі ми реалізуємо спосіб відстежувати рекорди для найпопулярнішої гри у місцевому залі ігрових автоматів.

Нам потрібно реалізувати 6 функцій, переважно повʼязаних із роботою з обʼєктом, який зберігає рекорди.

1. Створити нову таблицю рекордів

Напишіть функцію create_score_board, яка створює обʼєкт, що править за таблицю рекордів. Ключами цього обʼєкта будуть імена гравців, а значеннями - їхні рахунки. Для тестування потрібно безпосередньо включити до обʼєкта один запис. Цей початковий запис має складатися з "The Best Ever" як імені гравця та 1000000 як рахунку.

create_score_board
# returns an object with one initial entry

2. Додати гравців до таблиці рекордів

Щоб додати гравця до таблиці рекордів, реалізуйте функцію add_player. Вона приймає таблицю рекордів як вхідні дані та потребує два параметри: імʼя гравця та рахунок гравця. Функція повертає обʼєкт таблиці рекордів із доданим новим гравцем.

{"José Valim", 486373}
| add_player("Dave Thomas"; 0)
# => {"Dave Thomas": 0, "José Valim": 486373} -- in some order

Якщо гравець уже є в таблиці, поверніть таблицю без змін.

3. Видалити гравців із таблиці рекордів

Якщо гравці порушують правила залу ігрових автоматів, їх вручну видаляють із таблиці рекордів. Реалізуйте remove_player, яка приймає таблицю як вхідні дані та один параметр: імʼя гравця, якого потрібно видалити. Ця функція має видалити запис указаного гравця з таблиці та повернути нову таблицю. Якщо гравця спочатку не було в таблиці, з таблицею нічого не має статися; її слід повернути без змін.

{"Dave Thomas": 0} | remove_player("Dave Thomas")
# => {}

{"Dave Thomas": 0} | remove_player("Rose Fanaras")
# => {"Dave Thomas": 0}

4. Збільшити рахунок гравця

Якщо гравець завершує ще одну гру в залі ігрових автоматів, до попереднього рахунку в таблиці додається певна кількість очок. Реалізуйте update_score, яка приймає таблицю рекордів як вхідні дані та потребує два параметри: імʼя гравця й кількість очок для додавання. Функція має повернути таблицю рекордів після виконання оновлення.

{"Freyja Ćirić": 12771000} | update_score("Freyja Ćirić"; 73)
# => {"Freyja Ćirić": 12771073}

Ця функція має додати гравця до таблиці, якщо його там ще не було.

5. Застосувати бонусні очки за понеділок

У понеділок зал ігрових автоматів веде окрему таблицю рекордів. Наприкінці дня кожен гравець у цій таблиці отримує 100 додаткових очок.

Реалізуйте функцію apply_monday_bonus. Функція додає бонусні очки кожному гравцеві, зазначеному в цій таблиці.

{
  "Dave Thomas": 44,
  "Freyja Ćirić": 539,
  "José Valim": 265
}
| apply_monday_bonus
# => {"Dave Thomas": 144, "Freyja Ćirić": 639, "José Valim": 365}

6. Знайти загальний рахунок

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

Напишіть функцію total_score. Вона приймає таблицю рекордів як вхідні дані та повертає суму рахунків усіх гравців.

{
  "Dave Thomas": 44,
  "Freyja Ćirić": 539,
  "José Valim": 265
}
| total_score
# => 848
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
jq Exercism

Час розпочати Табло рекордів?

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