Преобразование ключа JSON первого уровня с помощью Python — решаемая

#python #json #python-3.x

#python #json #python-3.x

Вопрос:

У меня есть следующий JSON:

 {
    "1605855600000":
    [
        {
            "id": "1",
            "value": "1. Choice 1",
            "checked": true
        },
        {
            "id": "2",
            "value": "2. Choice 2",
            "checked": false
        },
        {
            "id": "3",
            "value": "3. Choice 3",
            "checked": false
        },
        {
            "id": "4",
            "value": "4. Choice 4",
            "checked": false
        },
        {
            "id": "5",
            "value": "5. Choice 5",
            "checked": false
        }
    ],
    "1604732400000":
    [
        {
            "id": "1",
            "value": "1. Choice 1",
            "checked": false
        },
        {
            "id": "2",
            "value": "2. Choice 2",
            "checked": false
        },
        {
            "id": "3",
            "value": "3. Choice 3",
            "checked": false
        },
        {
            "id": "4",
            "value": "4. Choice 4",
            "checked": false
        },
        {
            "id": "5",
            "value": "5. Choice 5",
            "checked": false
        }
    ]
}
 

Я не уверен в точной терминологии, но «ключи», такие как «1605855600000» и «1604732400000», являются временными метками UNIX, которые мне нужно преобразовать в Python.

Вот что у меня есть до сих пор:

 def convert_timestamp(obj):
    for key in obj.keys():
        timestamp = int(key) / 1000
        dt_object = datetime.fromtimestamp(timestamp)
        date = dt_object.strftime("%B %d, %Y")
        new_key = date
        if new_key != key:
            obj[new_key] = obj[key]
            del obj[key]
    return obj

data = json.loads(data, object_hook=convert_timestamp)
 

Однако ошибка, которую я получаю, гласит:
ValueError: invalid literal for int() with base 10: 'id'
это означает, что он обращается к уровню ниже того, что я пытаюсь изменить.

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

Конечный результат должен выглядеть примерно так:

 {
    "12 November, 2020":
    [
        {
            "id": "1",
            "value": "1. Choice 1",
            "checked": true
        },
...
 

Вот как я в конечном итоге решил это.

 json_data = json.loads(data)
dict_keys = json_data.keys()

timestamp = []
for x in dict_keys:
    date_val = int(x) / 1000
    dt_object = datetime.fromtimestamp(date_val)
    date = dt_object.strftime("%B %d, %Y")
    timestamp.append(date)

final_dict = dict(zip(timestamp, list(json_data.values())))

 

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

Комментарии:

1. Я бы рекомендовал прочитать ericlippert.com/2014/03/05/how-to-debug-small-programs .

Ответ №1:

Вам гораздо лучше создавать новый dict , чем возиться с ключами:

 import json
from datetime import datetime

data_str = '''{
    "1605855600000":
    [
        { "id": "1", "value": "1. Choice 1", "checked": true },
        { "id": "2", "value": "2. Choice 2", "checked": false },
        { "id": "3", "value": "3. Choice 3", "checked": false },
        { "id": "4", "value": "4. Choice 4", "checked": false },
        { "id": "5", "value": "5. Choice 5", "checked": false }
    ],
    "1604732400000":
    [
        { "id": "1", "value": "1. Choice 1", "checked": false },
        { "id": "2", "value": "2. Choice 2", "checked": false },
        { "id": "3", "value": "3. Choice 3", "checked": false },
        { "id": "4", "value": "4. Choice 4", "checked": false },
        { "id": "5", "value": "5. Choice 5", "checked": false }
    ]
}'''

def convert_timestamp(key):
    timestamp = int(key) / 1000
    dt_object = datetime.fromtimestamp(timestamp)
    return dt_object.strftime("%B %d, %Y")

def convert_keys(obj):
    return {convert_timestamp(key):val for (key,val) in obj.items()}

data = json.loads(data_str)

new_data = convert_keys(data)
print(new_data)
 

Вывод:

 {'November 20, 2020': [{'id': '1', 'value': '1. Choice 1', 'checked': True}, {'id': '2', 'value': '2. Choice 2', 'checked': False}, {'id': '3', 'value': '3. Choice 3', 'checked': False}, {'id': '4', 'value': '4. Choice 4', 'checked': False}, {'id': '5', 'value': '5. Choice 5', 'checked': False}], 'November 07, 2020': [{'id': '1', 'value': '1. Choice 1', 'checked': False}, {'id': '2', 'value': '2. Choice 2', 'checked': False}, {'id': '3', 'value': '3. Choice 3', 'checked': False}, {'id': '4', 'value': '4. Choice 4', 'checked': False}, {'id': '5', 'value': '5. Choice 5', 'checked': False}]}
 

Ответ №2:

Вы имели в виду:

 data = json.loads(data)

data = convert_timestamp(data)
 

Комментарии:

1. Даже всякий раз, когда я конвертирую в это, он возвращает только первый преобразованный ключ, но не второй. Я пытался изменить структуру return в цикле for, но безуспешно.

Ответ №3:

Вы неправильно object_hook использовали параметр json.loads .

Из документов

object_hook — это необязательная функция, которая будет вызываться с результатом декодирования любого объектного литерала (dict). Вместо dict будет использоваться возвращаемое значение object_hook . Эта функция может быть использована для реализации пользовательских декодеров (например, подсказок класса JSON-RPC).

Следовательно, он принимает первый объект, найденный ключом. Как @quamrana упомянул в своем ответе, вам нужно сделать:

 json_data = json.loads(data)
converted_data = convert_timestamp(json_data)
 

Кроме того, считается хорошей практикой не переопределять данные, а использовать отдельные переменные.

Комментарии:

1. Спасибо за разъяснение. Однако он по-прежнему возвращает только первое преобразуемое значение, как будто что-то не так в цикле, который не обращается ко всем значениям ключа.