Слияние диктов в диктаты без перезаписи всего диктата? - PullRequest
1 голос
/ 18 апреля 2020

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

При объединении я хочу сохранить все в моем уже существующем. json файле и обновлять только новые измененные значения из моего примера dict dict_01. Если ключевой или целый словарь не существует, я хочу добавить новый dict в dict, если скажем 'name_03' еще не существует.

import json
from pprint import pprint


json_filepath = 'database.json'

dict_01 = {"database": {"name_01": {"name": "name_01",
                                    "count": 10, 
                                    "size": "3"},
                        "name_03": {"name": "name_01",
                                    "count": 10, 
                                    "size": "3"}}}



with open(json_filepath, 'r', encoding="utf-8") as f:
    data = json.load(f)


pprint(data)

Кажется, это только заменяет мой текущий диктат. Поэтому вся существующая информация удаляется. Не то, что мне нужно.

data.update(dict_01)  # That doesn't do what I want it to do


with open(json_filepath, 'w+') as f:
    json.dump(data)

Пример содержимого database.json файла

{"database": {"name_01": {"count": 1,
                          "file_count": 1,
                          "folder_count": 0,
                          "hdd_master_name": "name_01_suffix",
                          "last_scanned": "14/04/20 15:55",
                          "name": "name_01",
                          "server_path": "root.txt",
                          "size": "0.18"},
              "name_02": {"all_types_count": 4,
                          "file_count": 8,
                          "folder_count": 0,
                          "hdd_master_name": "name_02_suffix",
                          "last_scanned": "14/04/20 15:55",
                          "name": "name_02",
                          "server_path": "...",
                          "size": "50.34"}}}

Результат, который я ищу:

{"database": {"name_01": {"count": 10,
                          "file_count": 1,
                          "folder_count": 0,
                          "hdd_master_name": "name_01_suffix",
                          "last_scanned": "14/04/20 15:55",
                          "name": "name_01",
                          "server_path": "root.txt",
                          "size": "3"},
              "name_02": {"all_types_count": 4,
                          "file_count": 8,
                          "folder_count": 0,
                          "hdd_master_name": "name_02_suffix",
                          "last_scanned": "14/04/20 15:55",
                          "name": "name_02",
                          "server_path": "...",
                          "size": "50.34"},
              "name_03": {"name": "name_01",
                          "count": 10, 
                          "size": "3"}}}

Ответы [ 5 ]

2 голосов
/ 18 апреля 2020

Попробуйте:

import collections
def dict_merge(dct, merge_dct):
    for k, v in merge_dct.items():
        if (k in dct and isinstance(dct[k], dict)
            and isinstance(merge_dct[k], collections.Mapping)):
            dict_merge(dct[k], merge_dct[k])
        else:
            dct[k] = merge_dct[k]
    return dct

Полный код

import json
import collections

with open("database.json", 'r', encoding="utf-8") as f:
    data = json.load(f)

dict_01 = {"database": {"name_01": {"name": "name_01",
                                    "count": 10, 
                                    "size": "3"},
                        "name_03": {"name": "name_01",
                                    "count": 10, 
                                    "size": "3"}}}

def dict_merge(dct, merge_dct):
    for k, v in merge_dct.items():
        if (k in dct and isinstance(dct[k], dict)
            and isinstance(merge_dct[k], collections.Mapping)):
            dict_merge(dct[k], merge_dct[k])
        else:
            dct[k] = merge_dct[k]
    return dct

out = dict_merge(data, dict_01)
print(out)
# {
#     "database": {
#         "name_01": {
#             "count": 10,
#             "file_count": 1,
#             "folder_count": 0,
#             "hdd_master_name": "name_01_suffix",
#             "last_scanned": "14/04/20 15:55",
#             "name": "name_01",
#             "server_path": "root.txt",
#             "size": "3"
#         },
#         "name_02": {
#             "all_types_count": 4,
#             "file_count": 8,
#             "folder_count": 0,
#             "hdd_master_name": "name_02_suffix",
#             "last_scanned": "14/04/20 15:55",
#             "name": "name_02",
#             "server_path": "...",
#             "size": "50.34"
#         },
#         "name_03": {
#             "name": "name_01",
#             "count": 10,
#             "size": "3"
#         }
#     }
# }

Источник: Рекурсивный словарь слияния в Python

1 голос
/ 20 апреля 2020

@ BenjaminK

Если вам нужно обновить данные рекурсивно; например; если db равно:

db_01 = {"database": {"name_01": {"name": "name_01",
                                    "count": 10, 
                                    "size": "3"},
                        "name_03": {"name": "name_01",
                                    "count": 10, 
                                    "size": "3"}}}

и словарь, который вы хотите обновить, это:

dict_to_update = {"database": {"name_03": {"father":{"name":"john"}}}}

Вам необходимо выполнить следующее;

Для Python2 .X ;

import collections

def update(db, dict2update):
    for k, v in dict2update.iteritems():
        if isinstance(v, collections.Mapping):
            db[k] = update(db.get(k, {}), v)
        else:
            db[k] = v
    return d

Для Python3 .X ;

import collections.abc

def update(db, dict2update):
    for k, v in dict2update.items():
        if isinstance(v, collections.abc.Mapping):
            db[k] = update(db.get(k, {}), v)
        else:
            db[k] = v
    return db

Вы можете обновить свою базу данных db_01 следующим образом;

update(db_01, dict_01)

После этого ваш db_01 будет;

{'database': {'name_01': {'name': 'name_01', 'count': 10, 'size': '3'},
  'name_03': {'name': 'name_01',
   'count': 10,
   'size': '3',
   'father': {'name': 'john'}}}}

Надеюсь, это поможет. Если нет, дайте мне знать. Happy Coding:)

1 голос
/ 18 апреля 2020

Для объединения 2-х диктов я бы использовал это:

def mergedicts(dict1, dict2):
   for k in set(dict1.keys()).union(dict2.keys()):
       if k in dict1 and k in dict2:
          if isinstance(dict1[k], dict) and isinstance(dict2[k], dict):
             yield (k, dict(mergedicts(dict1[k], dict2[k])))
          else:
             yield (k, dict2[k])
       elif k in dict1:
           yield (k, dict1[k])
       else:
          yield (k, dict2[k])

и:

dict1 = {1:{"a":"A"},2:{"b":"B"}}
dict2 = {2:{"c":"C"},3:{"d":"D"}}
print dict(mergedicts(dict1,dict2))

Какие отпечатки:

{1: {'a': 'A'}, 2: {'c': 'C', 'b': 'B'}, 3: {'d': 'D'}}
1 голос
/ 18 апреля 2020

Вам необходимо обновить данные ['база данных'] не данные . Код выглядит следующим образом:

import json
from pprint import pprint

json_filepath = 'database.json'

dict_01 = {"database": {"name_01": {"name": "name_01",
                                    "count": 10, 
                                    "size": "3"},
                        "name_03": {"name": "name_01",
                                    "count": 10, 
                                    "size": "3"}}}



with open(json_filepath, 'r', encoding="utf-8") as f:
    data = json.load(f)


# here is the change
data['database'].update(dict_01['database'])

pprint(data)

with open(json_filepath, 'w+') as f:
    json.dump(data)

Надеюсь, это поможет. :) Наслаждайтесь:)

1 голос
/ 18 апреля 2020
dict_01["database"] = {**dict_01["database"], **dict_02["database"]} 

Я проверял это.

Полный рабочий код:

dict_01 = {"database": {"name_01": {"name": "name_01",
                                    "count": 10, 
                                    "size": "3"},
                        "name_03": {"name": "name_01",
                                    "count": 10, 
                                    "size": "3"}}}

dict_02 = {"database": {"name_01": {"count": 1,
                          "file_count": 1,
                          "folder_count": 0,
                          "hdd_master_name": "name_01_suffix",
                          "last_scanned": "14/04/20 15:55",
                          "name": "name_01",
                          "server_path": "root.txt",
                          "size": "0.18"},
              "name_02": {"all_types_count": 4,
                          "file_count": 8,
                          "folder_count": 0,
                          "hdd_master_name": "name_02_suffix",
                          "last_scanned": "14/04/20 15:55",
                          "name": "name_02",
                          "server_path": "...",
                          "size": "50.34"}}}

dict_01["database"] = {**dict_01["database"], **dict_02["database"]} 
print(dict_01)

out:

{"database": {"name_01": {"count": 10,
                          "file_count": 1,
                          "folder_count": 0,
                          "hdd_master_name": "name_01_suffix",
                          "last_scanned": "14/04/20 15:55",
                          "name": "name_01",
                          "server_path": "root.txt",
                          "size": "3"},
              "name_02": {"all_types_count": 4,
                          "file_count": 8,
                          "folder_count": 0,
                          "hdd_master_name": "name_02_suffix",
                          "last_scanned": "14/04/20 15:55",
                          "name": "name_02",
                          "server_path": "...",
                          "size": "50.34"},
              "name_03": {"name": "name_01",
                          "count": 10, 
                          "size": "3"}}}
...