Как объединить два файла json в python вместо вложения для цикла

#python #json #performance #dictionary #merge

#python #json #Производительность #словарь #слияние

Вопрос:

Каждый раз, когда я получаю 500 записей из file1, чтобы присоединиться к file2, который содержит более 100000 записей, это занимает две минуты!!

 with open(file1,'r') as f1,open(file2,'r') as f2:
    a = json.load(f1)
    b = json.load(f2)
    list_a = []
    for i in range(len(a)):
        for n in range(len(b)):
            if b[n]["id"] == a[i]["id"]:
                list_a.append(dict(b[n], **a[i]))
with open(result,'w') as f3:
    json.dump(list_a, f3,sort_keys=True, ensure_ascii=False)
  

Файл1:

 [{ "id":"1", "name":"Tom" }, 
{ "id":"2", "name":"Jim" }, 
{ "id":"3", "name":"Bob" }, 
{ "id":"4", "name":"Jeny" },  
{ "id":"5", "name":"Lara" }, 
{ "id":"6", "name":"Lin" }, 
{ "id":"7", "name":"Kim" }, 
{ "id":"8", "name":"Jack" }, 
{ "id":"9", "name":"Tony" }]
  

Файл 2:

 [ { "id":"1", "Details":[ { "label":"jcc", "hooby":"Swimming" }, { "label":"hkt", "hooby":"Basketball" }, ] }, 
{ "id":"2", "Details":[ { "label":"NTC", "hooby":"Games" } ] } ]
  

Результат:

 [ { "id":"1", "name":"Tom", "Details":[ { "label":"jcc", "hooby":"Swimming" }, { "label":"hkt", "hooby":"Basketball" }, ] }, 
{ "id":"2", "name":"Jim", "Details":[ { "label":"NTC", "hooby":"Games" } ] } ] 
  

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

1. Создайте один или несколько словарей с идентификаторами в качестве ключей.

Ответ №1:

Ваш код выполняется за O(N*M) время (где N == len(a) и M == len(b) ), что слишком медленно для таких больших файлов. Вы можете запустить его за O(N M ) время, сначала создав сопоставление для a идентификаторов и используя его для поиска совпадающих b идентификаторов, например:

 import json

with open('file1') as f1, open('file2') as f2, open('file3', 'w') as f3:
    a = json.load(f1)
    b = json.load(f2)

    aid = {d['id']: d for d in a}
    list_a = [{k: v for d in (b_dict, aid[b_dict['id']]) for k, v in d.items()}
              for b_dict in b if b_dict['id'] in aid]

    json.dump(list_a, f3, sort_keys=True, ensure_ascii=False)
  

Если вы хотите, чтобы код был совместим с Python 2.x, вы можете использовать понимание словаря для объединения словарей (как показано выше). В Python 3.5 вы можете просто использовать распаковку, например {**d1, **d2} .

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

1. спасибо за ваш повтор, у меня есть тестовый набор в python3, но ошибка python2.7: list_a = [{** items, **a_map [элементы[«id»]]} для элементов в b, если элементы [«id»] в a_map] ^ SyntaxError: недопустимый синтаксис, как я могу это исправить. Большое спасибо!

2. и затем я обнаружил, что версии python < 3.5 не поддерживают выделенные выражения в dicts, но мне нужно сделать это в python2.7 можете ли вы помочь

3. @PythonBeggar: Вы можете использовать понимание по словарю вместо распаковки, если хотите сохранить совместимость с Python 2.x (см. Обновление).

Ответ №2:

У меня нет опыта, чтобы знать, ускорит ли это процесс. Решение, приведенное ниже Евгением Ярмашем, кажется более надежным. У меня также нет больших файлов для проверки скорости, но вы можете попробовать и посмотреть, ускорит ли итерацию использование коллекций. Мне самому было бы любопытно, изменит ли это что-нибудь:

 File1 = [ { "id":"1", "name":"Tom" }, { "id":"2", "name":"Jim" }, { "id":"3", "name":"Bob" }, { "id":"4", "name":"Jeny" }, { "id":"5", "name":"Lara" }, { "id":"6", "name":"Lin" }, { "id":"7", "name":"Kim" }, { "id":"8", "name":"Jack" }, { "id":"9", "name":"Tony" } ]
File2 = [ { "id":"1", "Details":[ { "label":"jcc", "hooby":"Swimming" }, { "label":"hkt", "hooby":"Basketball" }, ] }, { "id":"2", "Details":[ { "label":"NTC", "hooby":"Games" } ] } ] 

from collections import defaultdict

d = defaultdict(dict)
for l in (File1, File2):
    for elem in l:
        d[elem['id']].update(elem)
Result = dict(d)
  

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

1. спасибо за ваш ответ, но нам нужны данные, которые просто соответствуют file1, результат, который вы предоставляете, не включает