JSON

JSON (JavaScript Object Notation)  текстовый формат для описания и обмена данных, основанный на синтаксисе языка JavaScript. Другим похожим форматом является, например, XML. Однако формат JSON проще читается человеком и похож на синтаксис языка Python (описание JSON-объекта практически полностью соответствует синтаксису описания словаря).

Для работы с JSON в Python есть модуль json, позволяющий загружать описания объектов из формата JSON и, наоборот, сохранять объекты в формате JSON.

Преобразование из объектов языка программирования в строку называется сериализацией, а обратное преобразование — десериализацией. JSON — это настолько стандарт в мире IT, что модули сериализация и десериализации встроены примерно в любой нормальный язык программирования, кроме того есть куча библиотек, которые делают что-то сверху: либо дополнительную валидацию (например, модуль pydantic), либо делает сериализацию/десериализацию в 10 раз быстрее, но с некоторыми отходами от стандарта (например, модуль ujson).

Материалы для изучения

  1. Статья в википедии.
  2. Документация на модуль json (английская).
  3. Примеры работы с JSON по-русски

Пример сериализации и десериализации

import json

json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
'["foo", {"bar": ["baz", null, 1.0, 2]}]'

json.dumps(['Йоу!', {'"Вах!"': ('Рус', None, 1.0, 2)}])
'["\\u0419\\u043e\\u0443!", {"\\"\\u0412\\u0430\\u0445!\\"": ["\\u0420\\u0443\\u0441", null, 1.0, 2]}]'

json.dumps(['Йоу!', {'"Вах!"': ('Рус', None, 1.0, 2)}], separators=(',', ':'), ensure_ascii=False)
'["Йоу!",{"\\"Вах!\\"":["Рус",null,1.0,2]}]'

json.loads('["\\u0419\\u043e\\u0443!", {"\\"\\u0412\\u0430\\u0445!\\"": ["\\u0420\\u0443\\u0441", null, 1.0, 2]}]')
['Йоу!', {'"Вах!"': ['Рус', None, 1.0, 2]}]

Замечание по вводу-выводу

Данные можно брать либо из стандартного ввода, либо из файла input.txt. Выводить можно либо в стандартный вывод, либо в файл output.txt. Используемая кодировка для русских букв: UTF-8.

A: Считываем JSON

Программа получает на вход описание одного объекта в формате JSON. Программа должна вывести все пары ключ–значение этого объекта, разделяя их двоеточием. Используйте для этого функцию json.load. Выведите пары ключ–значение, разделяя их двоеточием и пробелом, упорядочив по ключу. Кавычки вокруг строк выводить не надо, см. пример.

{ "street": "Большая Дмитровка", "city": "Москва", "country": "Россия" }
city: Москва country: Россия street: Большая Дмитровка

B: Записываем JSON

Решите обратную задачу. Программа получает на вход пары ключ–значение, разделённых двоеточием и пробелом. Создайте словарь из этих пар (все значения считаем строками) и выведите его в формате JSON.

Если вас смущают строки вида "\u041c\u043e\u0441\u043a\u0432\u0430" в выводе, используете параметр ensure_ascii=False. А можете оставить, как есть.

city: Москва country: Россия street: Большая Дмитровка
{ "street": "Большая Дмитровка", "city": "Москва", "country": "Россия" }

C: Разные типы JSON

Объекты в JSON могут быть следующих типов

Вам дан JSON-объект, являющийся списком. Пройдитесь по его элементам, и со всеми элементами сделайте следующее:

Выведите полученный JSON.

["Hello", 179, 0.5, true, null, [1, 2, 3], {"key": "value"}]
["Hello!", 180, 1.5, false, [1, 2, 3, 1, 2, 3], {"key": "value", "newkey": null}]

D: Обновление объекта

Даны два объекта JSON. Необходимо объединить их вместе по следующему правилу: результат берёт все атрибуты из первого объекта, а если во втором объекте содержатся атрибуты с такими же ключами, как и у первого объекта, или отсутстсвующие в первом объекте, то они также добавляются в результат.

Программа получает на вход JSON-список из двух JSON-объектов и должна вывести один JSON-объект.

[{"firstName": "Иван", "middleName": "Петров", "birthDate": "2001/02/29"}, {"city": "Moscow", "birthDate": "2001/02/28"}]
{"middleName": "Петров", "firstName": "Иван", "city": "Moscow", "birthDate": "2001/02/28"}

E: Восстановление недостающих атрибутов

Дан список объектов JSON, у них могут быть разные атрибуты. При этом у разных объектов может быть разный набор атрибутов: некоторых атрибутов может не хватать. Добавьте ко всем объектам недостающие атрибуты: создайте их, записав туда значения null.

Атрибут у некоторого объекта считается отсутствующим, если у какого-то другого объекта есть атрибут с таким ключом, а у этого объекта его нет.

[{"firstName": "Иван", "middleName": "Петров", "birthDate": "2001/02/29"}, {"firstName": "Пётр", "middleName": "Иванов", "city": "Moscow"}]
[{"city": null, "middleName": "Петров", "birthDate": "2001/02/29", "firstName": "Иван"}, {"city": "Moscow", "middleName": "Иванов", "birthDate": null, "firstName": "Пётр"}]

F: Рекурсивное суммирование

Дан объект JSON, являющийся списком. Элементами списка могут быть только числа или аналогичные списки, содержащие числа и вложенные списки и т.д. Найдите сумму всех чисел во всех списках.

Сумма пустого списка равна 0.

[1, 2, [3, [4, 5]], [6, []]]
21

G: Рекурсивный обход

Дан объект JSON, являющийся словарём. Атрибутами словаря могут быть числа, строки или аналогичные словари.

Выведите все пары ключ–значение словаря, рекурсивно выводя значения атрибутов всех дочерних словарей. При выводе атрибутов необходимо перечислять имена всех ключей, начиная с верхнего уровня, разделяя их точками (см. пример).

Выводите ключи в лексикографическом порядке.

{ "firstName": "Иван", "lastName": "Иванов", "birthDate": { "day": 10, "month": "October", "year": 2002 }, "address": { "streetAddress": "Московское ш., 101, кв.101", "city": { "region": "Ленинградская область", "type": "город", "cityName": "Сосново" }, "postalCode": "101101" } }
address.city.cityName: Сосново address.city.region: Ленинградская область address.city.type: город address.postalCode: 101101 address.streetAddress: Московское ш., 101, кв.101 birthDate.day: 10 birthDate.month: October birthDate.year: 2002 firstName: Иван lastName: Иванов

H★: Рекурсивное обновление

Даны два объекта JSON, являющихся словарём. Атрибутами словаря могут быть числа, строки или аналогичные словари (как в предыдущей задаче).

Выполните обновление первого объекта данными из второго объекта. При этом если атрибут с одинаковым названием и в первом, и во втором объекте является словарём, необходимо выполнить процедуру обновление рекурсивно для этого объекта.

Если же атрибут с одинаковым ключом является словарём только у одного из двух объектов, то берётся значение второго объекта.

Программа получает на вход JSON-список из двух JSON-объектов и должна вывести один JSON-объект.

[ { "a": 123, "c": "qwe", "d": { "da": 10, "db": 20, "dz": { "x": {} } } }, { "a": {"a1": "abc"}, "b": 456, "d": { "db": 30, "dc": 40, "dz": { "y": 0 } } } ]
{ "b": 456, "d": { "dc": 40, "db": 30, "dz": { "x": {}, "y": 0 }, "da": 10 }, "c": "qwe", "a": { "a1": "abc" } }

Работа с реальными данными

В этом задании будут использоваться данные JSON с сайта data.mos.ru. При этом данные в ejudge перекодированы в UTF8, на сайте data.mos.ru данные лежат в кодировке CP1251.

Для изучения структуры JSON, скачанных с data.mos.ru, можете воспользоваться этим online-просмотрщиком JSON или найти другое приложение.

В большинстве задач тесты такие, что ответ однозначный (например, станция с наибольшим числом выходов только одна).

Q: Выходы станций метро

Изучите набор данных “Входы и выходы вестибюлей станций Московского метрополитена”. Возможно, данные на mos.ru стухли. Тогда смотрите формат вот вот здесь.

Под станцией мы будем подразумевать уникальную комбинацию названия станции и названия линии. Например, станция Арбатская Филёвской линии и станция Арбатская Арбатско-Покровской линии — это разные станции.

Определите станцию с самым большим числом выходов, самую северную, самую южную, самую западную, самую восточную станции. Выводите название станции и название линии метро. В первой строке также выведите количество выходов с этой станции.

Пример вывода (неправильный, для некоторого сокращённого набора данных) ниже. Следуйте этому примеру.

Больше всего выходов: Красногвардейская, Замоскворецкая линия, 2 Самая северная: Алтуфьево, Серпуховско-Тимирязевская линия Самая южная: Орехово, Замоскворецкая линия Самая западная: Строгино, Арбатско-Покровская линия Самая восточная: Лермонтовский проспект, Таганско-Краснопресненская линия

R: Общественное питание

Изучите набор данных “Общественное питание в Москве”.

Под “заведением” будем подразумевать один объект в этой базе. У заведения бывают разные атрибуты: район, количество посадочных мест, вид (кафе, столовая, ресторан и т.д.). Бывают сетевые заведения.

Найдите район Москвы, в котором находится больше всего заведений. Выведите район и количество заведений в нём.

Определите все виды заведений. Для каждого вида найдите самое большое заведение этого вида. Выведите название заведения и количество мест в нём. Упорядочите строки по виду заведения.

Определите сеть с самым большим числом заведений. Выведите название сети и количество заведений сети.

Определите сеть с самым большим суммарным числом посадочных мест. Выведите название сети и количество мест в заведениях этой сети.

Пример вывода (неправильный, для некоторого сокращённого набора данных) ниже. Следуйте этому примеру.

Район с наибольшим числом заведений: Тверской район, 3 Самое большое заведение вида бар: Гадкий кайот, 120 Самое большое заведение вида кафе: Mesto 20.1, 49 Самое большое заведение вида предприятие быстрого обслуживания: KFC, 60 Самое большое заведение вида ресторан: Караоке «City Voice», 112 Самое большое заведение вида столовая: ВЕРОНА СТОЛОВАЯ ШКОЛЫ № 1467, 240 Самая большая сеть по числу заведений: KFC, 3 Самая большая сеть по числу мест: KFC, 80

S: Бассейны

Изучите набор данных “Бассейны плавательные крытые”.

Данные о бассейнах содержат информацию о зимнем и летнем периоде работы. Мы будем рассматривать только летний период.

Вы хотите пойти в бассейн, например, с 08:00 до 09:00 в понедельник. Для этого вы хотите найти бассейн, который работает в это время. Вы любите плавать по длинным дорожкам, поэтому из всех работающих в это время бассейнов вы выберете бассейн с наибольшей длиной дорожки. При равной длине дорожки вы выберете бассейн с наибольшей шириной.

Обратите внимание, что у некоторых бассейнов время закрытия может быть после полуночи, например, 08:00-00:30. Мы же считаем, что вы не любите ходить в бассейн по ночам, поэтому время вашего посещения бассейна будет заканчиваться раньше полуночи. Ну и помимо этого вас могут ждать различные сюрпризы в данных. Поэтому обязательно скачайте оригинальный набор данных и поэкспериментируйте с ним.

Определите бассейн, который вы хотите посетить. В случае нескольких подходящих бассейнов, выведите адрес одного (любого) из них.

В этой задаче входные данные будут отличаться от оригинальных данных с data.mos.ru. А именно, в начало списка бассейнов будет добавлен ещё один объект с информацией о том, когда вы хотите посетить бассейн. Входные данные будут иметь следующий вид:

[    // В начале - объект с информацией о времени посещения
    {'Hours': '08:00-09:00', 'DayOfWeek': 'понедельник'}

    // Затем - объекты с данным о бассейнах с data.mos.ru
    {
        "NameSummer": "бассейн плавательный крытый",
        "global_id": 1047358249
    //  и т.д.
    }
]

Выведите в первой строке через пробел длину и ширину бассейна, в который вы пойдёте. Во второй строке выведите адрес этого бассейна.

Пример вывода (неправильный, для некоторого сокращённого набора данных) ниже. Следуйте этому примеру.

25 16 Писцовая улица, дом 12, строение 1

T: Велосипедные дорожки

Вспомните, как считать расстояние между двумя точками на шаре. При этом можно предполагать, что в пределах Москвы поверхность Земли является плоской.

Изучите набор данных “Дорожки велосипедные”.

Найдите самую длинную велодорожку. Выведите описание расположения этой дорожки и её длину в метрах.

Обратите внимание, что велодорожка может состоять из нескольких сегментов (ломаных линий). Под длиной велодорожки подразумевается сумма длин всех сегментов. В первом тесте (см. пример) длина ответа как раз является такой суммой.

Пример вывода (неправильный, для некоторого сокращённого набора данных) ниже. Следуйте этому примеру.

от Юрловского проезда дом 14 до Сельскохозяйственной дом 64 2251