Mail.ruПочтаМой МирОдноклассникиВКонтактеИгрыЗнакомстваНовостиКалендарьОблакоЗаметкиВсе проекты

Python нужна помощь

mirovinger mirovinger Ученик (87), закрыт 1 год назад
Задача
Найдите различия между двумя JSON-файлами.
Список параметров для отслеживания - diff_list = ["services", "staff", "datetime"]

Мой код:
 import json 

with open('json_old.json') as f1, open('json_new.json') as f2:
data_old = json.load(f1)
data_new = json.load(f2)

diff_list = ["services", "staff", "datetime"]

changes = []
for key in diff_list:
if key in data_old and key in data_new and data_old[key] != data_new[key]:
changes.append(key)

result = {}
for key in changes:
result[key] = data_new[key]

with open('result.json', 'w') as f:
json.dump(result, f)

print(result)
Мой код не находит различия

Прошу помощи, что делаю не так?

Данные, загруженные из json_old.json:
 {"company_id": 111111, "resource": "record", "resource_id": 406155061, "status": "create", "data": {"id": 11111111, "company_id": 111111, "services": [{"id": 9035445, "title": "\u0421\u0442\u0440\u0438\u0436\u043a\u0430", "cost": 1500, "cost_per_unit": 1500, "first_cost": 1500, "amount": 1}], "goods_transactions": [], "staff": {"id": 1819441, "name": "\u041c\u0430\u0441\u0442\u0435\u0440"}, "client": {"id": 130345867, "name": "\u041a\u043b\u0438\u0435\u043d\u0442", "phone": "79111111111", "success_visits_count": 2, "fail_visits_count": 0}, "clients_count": 1, "datetime": "2022-01-25T11:00:00+03:00", "create_date": "2022-01-22T00:54:00+03:00", "online": false, "attendance": 0, "confirmed": 1, "seance_length": 3600, "length": 3600, "master_request": 1, "visit_id": 346427049, "created_user_id": 10573443, "deleted": false, "paid_full": 0, "last_change_date": "2022-01-22T00:54:00+03:00", "record_labels": "", "date": "2022-01-22 10:00:00"}} 
Данные, загруженные из json_new.json:
 :{"company_id": 111111, "resource": "record", "resource_id": 406155061, "status": "create", "data": {"id": 11111111, "company_id": 111111, "services": [{"id": 22222225, "title": "\u0421\u0442\u0440\u0438\u0436\u043a\u0430", "cost": 1500, "cost_per_unit": 1500, "first_cost": 1500, "amount": 1}], "goods_transactions": [], "staff": {"id": 1819441, "name": "\u041c\u0430\u0441\u0442\u0435\u0440"}, "client": {"id": 130345867, "name": "\u041a\u043b\u0438\u0435\u043d\u0442", "phone": "79111111111", "success_visits_count": 2, "fail_visits_count": 0}, "clients_count": 1, "datetime": "2022-01-25T13:00:00+03:00", "create_date": "2022-01-22T00:54:00+03:00", "online": false, "attendance": 2, "confirmed": 1, "seance_length": 3600, "length": 3600, "master_request": 1, "visit_id": 346427049, "created_user_id": 10573443, "deleted": false, "paid_full": 1, "last_change_date": "2022-01-22T00:54:00+03:00", "record_labels": "", "date": "2022-01-22 10:00:00"}} 
Различия в 'json_new.json'. Которые нужно найти.
  {'services': [{'id': 22222225, 'title': 'Стрижка', 'cost': 1500, 'cost_per_unit': 1500, 'first_cost': 1500, 'amount': 1}], 'datetime': '2022-01-25T13:00:00+03:00'} 
Лучший ответ
Алексей Пинчук Мудрец (16117) 1 год назад
«Не так» делается вот что.

Структура data_xxx иерархическая, со многими уровнями вложенности. В то же время если посмотреть, что выдаёт data_xxx:
 for data in data_old:  print(data)  
то увидим
 company_id 
resource
resource_id
status
data
то есть ключи только верхнего уровня. Соответственно, условие
 if key in data_old and key in data_new and data_old[key] != data_new[key]:  
проверяет различие только на верхнем уровне, не заглядывая внутрь контейнера, поэтому код и не находит различий (key in data_old всегда False).

Поставив диагноз, приступим к лечению. Нам надо не просто пройтись по всем ключам контейнера, но и заглянуть внутрь каждого значения, на случай, если значение само является контейнером.

Из-за обработки всякий ситуаций код получился немного громоздким.
 def get_difference(container1, container2, diff_list): 

def get_deep_difference(container1, container2, deepcheck):
nonlocal changes, diff_list
diff = False
try:
# Основной цикл по словарю
for key in container1.keys():
check = deepcheck or diff_list and key in diff_list
try:
if get_deep_difference(container1[key], container2[key], check):
if diff_list and key in diff_list: changes[key] = container2[key]
if deepcheck: return True
diff = True
except KeyError: # В container2 отсутствует key
if diff_list and key in diff_list: changes[key] = None
if deepcheck: return True
diff = True

except AttributeError: # container1 не словарь

if isinstance(container1, str): # строка особый тип, обрабатывается особо
return container1 != container2

try:
# Обработка других типов контейнеров (список, кортеж, множество)
for index, elem in enumerate(container1):
try:
if get_deep_difference(container1[index], container2[index], deepcheck):
if deepcheck: return True
diff = True
except IndexError: return True

except TypeError: return container1 != container2

return diff
# End of get_deep_difference

changes = dict()
get_deep_difference(container1, container2, False)
return changes
# End of get_difference

И использование:
 result = get_difference(data_old, data_new, diff_list) 
print(result)
Проверил на твоих данных, result получился таким:
 {'services': [{'id': 22222225, 'title': 'Стрижка', 'cost': 1500, 'cost_per_unit': 1500, 'first_cost': 1500, 'amount': 1}], 'datetime': '2022-01-25T13:00:00+03:00'} 
Остальные ответы
John Reeves Ученик (228) 1 год назад
import json

# Заданный список параметров для отслеживания
diff_list = ["services", "staff", "datetime"]

# Открытие и чтение первого JSON-файла
with open('file1.json', 'r') as f1:
data1 = json.load(f1)

# Открытие и чтение второго JSON-файла
with open('file2.json', 'r') as f2:
data2 = json.load(f2)

# Поиск различий в значениях заданных ключей в двух JSON-файлах
for param in diff_list:
if data1[param] != data2[param]:
print(f"Различие в значении ключа {param}:")
print(f"Файл 1: {data1[param]}")
print(f"Файл 2: {data2[param]}")

mirovinger mirovingerУченик (87) 1 год назад
В результате выпадает ошибка KeyError.
Надежда Красильникова Ученик (212) 4 месяца назад
import json

def get_difference(container1, container2, diff_list=None):
"""
Возвращает словарь с различиями между двумя контейнерами.

:param container1: Первый контейнер для сравнения.
:type container1: dict, list, tuple, set или str.
:param container2: Второй контейнер для сравнения.
:type container2: dict, list, tuple, set или str.
:param diff_list: Список ключей, значения которых должны быть включены в результирующий словарь,
если они отличаются. Если не указан, будут включены все отличающиеся значения.
:type diff_list: list или None.
:return: Словарь с различиями между двумя контейнерами.
:rtype: dict.
"""
def get_deep_difference(container1, container2, changes, deepcheck):
"""
Рекурсивная функция для сравнения двух контейнеров.

:param container1: Первый контейнер для сравнения.
:type container1: dict, list, tuple, set или str.
:param container2: Второй контейнер для сравнения.
:type container2: dict, list, tuple, set или str.
:param changes: Словарь с различиями между двумя контейнерами.
:type changes: dict.
:param deepcheck: Флаг, указывающий, следует ли выполнять глубокое сравнение.
:type deepcheck: bool.
:return: True, если контейнеры отличаются, и False в противном случае.
:rtype: bool.
"""
diff = False
if isinstance(container1, dict):
for key in container1.keys():
check = deepcheck or diff_list and key in diff_list
if key in container2:
if get_deep_difference(container1[key], container2[key], changes, check):
if diff_list and key in diff_list:
changes[key] = container2[key]
if deepcheck:
return True
diff = True
else:
if diff_list and key in diff_list:
changes[key] = None
if deepcheck:
return True
diff = True
elif isinstance(container1, (list, tuple, set)):
if len(container1) != len(container2):
return True
for index, elem in enumerate(container1):
if get_deep_difference(container1[index], container2[index], changes, deepcheck):
if deepcheck:
return True
diff = True
else:
if container1 != container2:
return True
return diff

changes = dict()
get_deep_difference(container1, container2, changes, False)
return changes

with open('json_new.json', 'r') as f:
data_old = json.load(f)

with open('json_old.json', 'r') as f:
data_new = json.load(f)

diff_list = ["services", "staff", "datetime"]
result = get_difference(data_old, data_new, diff_list)
print(result)
Похожие вопросы