Я пытаюсь объединить два json, хранящихся в словарях python. Здесь первый словарь является родителем, в который вливается второй словарь. На самом деле второй словарь представляет собой вторую строку в файле TSV, содержащую следующую запись массива json.
Моя программа пытается прочитать файл TSV построчно и объединить их в один вложенный json.
Рассмотрим два словаря:
Родительский словарь dict1: {"CA": [{"Marin": [{"zip":1}], "population":10000}]}
и,
dict2: {"CA": {"Marin": {"zip":2}}}
Примечание: dict1
является источником правды в отношении правильной структуры json.
Здесь, как видите, я хотел бы добавить zip: 2
к округу Марин штата Калифорния.
Вот мой код слияния:
class MyClass:
# merges two lines containing json arrays inside nested json
def merge_lines(dict1: dict, dict2: dict) -> dict:
for key in dict1:
if key in dict2:
if isinstance(dict1[key], dict):
MyClass.merge_lines(dict1[key], dict2[key])
elif isinstance(dict1[key], list):
to_be_merged_list = [dict2[key]]
dict1[key].extend(to_be_merged_list)
return dict1
Ниже показано, как я пытаюсь проверить:
def test_nested_json_arrays(self):
d1 = {"CA": [{"Marin": [{"zip":1}], "population":10000}]}
d2 = {"CA": {"Marin": {"zip":2}}}
expected_result = {"CA": [{"Marin": [{"zip":1}, {"zip":2}], "population":1000}]}
actual = MyClass.merge_lines(d1, d2)
assert expected_result == actual
Однако я получаю следующий результат:
E AssertionError: assert {'CA': [{'Mar...tion': 1000}]} == {'CA': [{'Mari... {'zip': 2}}]}
E Differing items:
E {'CA': [{'Marin': [{'zip': 1}, {'zip': 2}], 'population': 1000}]} != {'CA': [{'Marin': [{'zip': 1}], 'population': 10000}, {'Marin': {'zip': 2}}]}
E Full diff:
E - {'CA': [{'Marin': [{'zip': 1}, {'zip': 2}], 'population': 1000}]}
E + {'CA': [{'Marin': [{'zip': 1}], 'population': 10000}, {'Marin': {'zip': 2}}]}
Может ли кто-нибудь помочь мне выяснить изменения, необходимые в коде, чтобы исправить это? Примечание: имена полей не являются постоянными, и это может применяться к любой комбинации страны, штата, округа, почтового индекса и других вложенных атрибутов.
Я хочу, чтобы это было так: {'CA': [{'Marin': [{'zip': 1}, {'zip': 2}], 'population': 1000}]}
.. {'zip':2}
должно быть с «Марин».
dict1 = {"CA": [{"Marin": [{"zip":1}], "population":10000}]}
dict2 = {"CA": {"Marin": {"zip":2}}}
Глядя на dict2
:
dict2
, содержащее ключ k
(в данном случае k = "CA"
)dict2[k]
сам по себе является словарем, который содержит одну (или более) пару ключ (c = "Marin"
) - значение (z
)z
теперь это словарь, который вам небезразличен.Глядя на dict1
:
county_info
в dict1[k]
вам нужен тот, у которого есть ключ c
.county_info[c]
) — это список, к которому вы хотите добавить z
Итак, давайте сделаем это:
def merge_lines(dict1, dict2):
for k, v in dict2.items():
for c, z in v.items():
# Find the element of dict1[k] that has the key c:
for county_info in dict1[k]:
if c in county_info:
county_info[c].append(z)
break
Поскольку функция изменяет dict1
на месте, запуск merge_lines(dict1, dict2)
дает нам модифицированный dict1
, который выглядит так, как вы ожидаете:
{'CA': [{'Marin': [{'zip': 1}, {'zip': 2}], 'population': 10000}]}
Это более общий подход, при котором d1
обновляется с учетом изменений, содержащихся в d2
.
Конечно, вы должны предоставить больше примеров обновлений от d2
, чтобы увидеть, работает ли мое решение во всех случаях.
#!/usr/bin/env python3
d1 = {"CA": [{"Marin": [{"zip": 1}], "population": 10000}]}
d2 = {"CA": {"Marin": {"zip": 2}}}
# read update data from d2 and append new values to d1
def update(d1, d2):
for key, value in d2.items():
if key in d1:
for key1, value1 in value.items():
if key1 in d1[key][0]:
d1[key][0][key1].append(value1)
else:
d1[key][0][key1] = [value1]
else:
d1[key] = [value]
return d1
print(update(d1, d2))
Что не так с "результатом ниже"? Какой результат вы хотели?