#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, результат, который вы предоставляете, не включает