Как сохранить diff of dict при вставке значения? - PullRequest
4 голосов
/ 16 июня 2019

Мне нужно иметь эффективный словарь различий, который говорит мне, в чем разница между основным словарем в определенный момент времени и сейчас.

Мне нужен полный путь к измененному, а не только значение, которое изменилось.

например:

primary_dict = {'a': 5, 'b':{'c': 9}, 'd':10}

и разница будет

diff_dict = {'a':6, 'b':{'c':8}}

сказать, что в настоящее время

primary_dict = {'a':6, 'b':{'c':8}, 'd':10}

Я могу создать разность, когда значения добавляются к dict

Я смотрел в Интернете, но нашел только сравнения между двумя словарями, и это было бы неэффективно, потому что словарь, который мне нужен для сравнения, массивный, его сохранение 2 раза и рекурсивное отображение всего этого, кажется, много работают для рассматриваемой проблемы

EDIT: Изменен вопрос, чтобы быть более точным. как я был уведомлен, вопрос, который отражает мои потребности: Как получить изменения в словаре с течением времени, не создавая новую переменную? Спасибо @CristiFati и @Vishnudev за исправления

Ответы [ 6 ]

0 голосов
/ 16 июня 2019

Вы можете использовать следующий код Python для получения разницы между двумя словарями:

before_change = {'a': 5, 'b':{'c': 9}, 'd':10}
after_change = {'a': 6, 'b':{'c':8}, 'd':10}

bc_values = list(before_change.values())
ac_values = list(after_change.values())
ac_keys = list(after_change.keys())

for item in range(len(bc_values)):
 if ac_values[item] == bc_values[item] :
   after_change.pop(ac_keys[item])

print(after_change)

Вывод этого кода:

{'a': 6, 'b': {'c': 8}}
0 голосов
/ 16 июня 2019

Вы можете использовать подсказку понимания:

actual_dict = {'a': 5, 'b':{'c': 9}, 'd':10}
diff_dict = {'a':6, 'b':{'c':8}}

primary_dict = {x: actual_dict[x] if x not in diff_dict.keys() else diff_dict[x] for x in actual_dict.keys()}

print(primary_dict)

Вывод:

{'a': 6, 'b': {'c ': 8},' d ': 10}

0 голосов
/ 16 июня 2019

Подобный вопрос уже существует: [SO]: Как получить разницу между двумя словарями в Python? .
Вы можете использовать рекурсивный подход.

code.py

#!/usr/bin/env python3

import sys


def dummy_dict_diff(initial, final):
    ret = dict()
    for final_key, final_val in final.items():
        if final_key not in initial:  # Handle new keys
            ret[final_key] = final_val
            continue
        initial_val = initial[final_key]
        if final_val != initial_val:
            if type(final_val) != type(initial_val):
                ret[final_key] = final_val
            elif isinstance(final_val, (dict,)):
                ret[final_key] = dummy_dict_diff(initial_val, final_val)
            elif isinstance(final_val, (list, tuple)):
                ret[final_key] = final_val  # This would also require sequence diffs
            else:
                ret[final_key] = final_val
    deleted_keys = [item for item in initial if item not in final]  # Deleted keys
    for deleted_key in deleted_keys:
        ret[deleted_key] = initial[deleted_key]
    return ret


def main():
    before = {
        "a": 5,
        "b": {
            "c": 9
        },
        "d": 10
    }

    after = {
        "a": 6,
        "b": {
            "c": 8
        },
        "d": 10
    }

    print("Difference: {:}".format(dummy_dict_diff(before, after)))


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()
    print("\nDone.")

Примечания

  • Есть некоторые случаи, которые в настоящее время не обрабатываются. Обработка их потребует больше кода (и, как следствие, будет работать медленнее):
    1. Последовательность (например, список , кортеж ) значений. Теперь это окончательное значение (регистр по умолчанию)

выход

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q056617962]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" code.py
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] on win32

Difference: {'a': 6, 'b': {'c': 8}}

Done.
0 голосов
/ 16 июня 2019

Комплексное решение (на основе set операций и рекурсивной функции ) для расширенных сложных словарей ввода:

Как сказано в названии, условие интереса - "при вставке значения" .

# extended input samples
before_change = {'a': 5, 'b': {'c': 9}, 'd': 10, 'g': {'h': {'k': 100}}}
after_change = {'a': 6, 'b': {'c': 9, 'f': 1}, 'd': 10, 'g': {'h': {'k': 300}}, 'e': 11}


def dict_diff(before, after):
    """Compute difference between dictionaries.
       Fetchs path to the innermost changed item"""

    new_keys = set(before) ^ set(after)
    diff = {k: after[k] for k in new_keys} # detecting new keys/items beforehand

    for k in set(before) & set(after):  # process intersected keys
        if before[k] != after[k]:
            if type(before[k]) is dict and type(after[k]) is dict:
                inner_diff = dict_diff(before[k], after[k])
                if inner_diff: diff[k] = inner_diff
            else:
                diff[k] = after[k]
    return diff

print(dict_diff(before_change, after_change))

Выход:

{'e': 11, 'b': {'f': 1}, 'g': {'h': {'k': 300}}, 'a': 6}
0 голосов
/ 16 июня 2019

Возможно, у OOPS может быть решение.

Словарь может быть отредактирован только публичной функцией с возможностью создания журнала изменений.

0 голосов
/ 16 июня 2019

Используйте библиотеку dictdiffer

>>> from dictdiffer import diff
>>> before_change = {'a': 5, 'b':{'c': 9}, 'd':10}
>>> after_change = {'a': 6, 'b':{'c':8, 'd': 10}, 'd':10}
>>> list(diff(before_change, after_change))
[('change', 'a', (5, 6)), ('change', 'b.c', (9, 8)), ('add', 'b', [('d', 10)])]

Для удаленных ключей

>>> before_change = {'a': 5, 'b':{'c': 9}, 'd':10}
>>> after_change = {'a': 6, 'b':{'d': 10}, 'd':10}
>>> list(diff(before_change, after_change))
[('change', 'a', (5, 6)), ('add', 'b', [('d', 10)]), ('remove', 'b', [('c', 9)])]
...