Skip to content

Instantly share code, notes, and snippets.

@PoisonousJohn
Created May 15, 2019 16:46
Show Gist options
  • Save PoisonousJohn/7e88a13e8d1eb9f671ce8e19efd262cb to your computer and use it in GitHub Desktop.
Save PoisonousJohn/7e88a13e8d1eb9f671ce8e19efd262cb to your computer and use it in GitHub Desktop.
deep update for python dicts
import copy
import itertools
def update_list_by_dict(target: list, value: dict):
"""
Updates a list using keys from dictionary
May be helpful if you want a fuzzy update of a list
If key greater than list size, list will be extended
If list value is dict, it's deep updated
"""
for k, v in value.items():
idx = int(k)
if idx >= len(target):
target.extend(itertools.repeat(None, idx - len(target) + 1))
if isinstance(target[idx], dict) and isinstance(v, dict):
deepupdate(target[idx], v)
else:
target[idx] = v
def deepupdate(target: dict, update: dict):
"""Deep update target dict with update
For each k,v in update: if k doesn't exist in target, it is deep copied from
update to target.
Nested lists are extend if you update by the list and updated if you update by dictionary
"""
for k, v in update.items():
curr_val = None
if isinstance(target, dict):
if k not in target:
target[k] = copy.deepcopy(v)
curr_val = target[k]
if isinstance(curr_val, list):
if isinstance(v, list):
curr_val.extend(copy.deepcopy(v))
elif isinstance(v, dict):
update_list_by_dict(curr_val, v)
else:
curr_val.extend(v)
elif isinstance(curr_val, dict):
deepupdate(target[k], v)
elif isinstance(curr_val, set):
if not k in target:
target[k] = v.copy()
else:
target[k].update(v.copy())
else:
target[k] = copy.copy(v)
from .dict_utils import deepupdate, update_list_by_dict
def test_update_list_by_dict():
l = []
update_list_by_dict(l, {0: 1, 3: 4})
assert l == [1, None, None, 4]
update_list_by_dict(l, {2: 3})
assert l == [1, None, 3, 4]
update_list_by_dict(l, {0: 0})
assert l == [0, None, 3, 4]
update_list_by_dict(l, {0: {'k1': {'k1.1': 'v1.1', 'k1.2': 'v1.2'}}})
assert l == [{'k1': {'k1.1': 'v1.1', 'k1.2': 'v1.2'}}, None, 3, 4]
update_list_by_dict(l, {0: {'k1': {'k1.1': 'v1.1*'}}})
assert l == [{'k1': {'k1.1': 'v1.1*', 'k1.2': 'v1.2'}}, None, 3, 4]
def test_deepupdate():
d = {}
deepupdate(d, {'k': 'v'})
assert d == {'k': 'v'}
deepupdate(d, {'k': {'k1': 1, 'k2': 2}})
assert d == {'k': {'k1': 1, 'k2': 2}}
deepupdate(d, {'k': {'k1': 0, }})
assert d == {'k': {'k1': 0, 'k2': 2}}
deepupdate(d, {'l': []})
assert d == {'k': {'k1': 0, 'k2': 2}, 'l': []}
deepupdate(d, {'l': [1]})
assert d == {'k': {'k1': 0, 'k2': 2}, 'l': [1]}
deepupdate(d, {'l': {0: 2}})
assert d == {'k': {'k1': 0, 'k2': 2}, 'l': [2]}
deepupdate(d, {'l': {3: 3}})
assert d == {'k': {'k1': 0, 'k2': 2}, 'l': [2, None, None, 3]}
deepupdate(d, {'l': {0: {'k1': {'k1.1': 'v1.1', 'k1.2': 'v1.2'}}}})
assert d == {'k': {'k1': 0, 'k2': 2}, 'l': [{'k1': {'k1.1': 'v1.1', 'k1.2': 'v1.2'}}, None, None, 3]}
deepupdate(d, {'l': {0: {'k1': {'k1.1': 'v1.1*'}}}})
assert d == {'k': {'k1': 0, 'k2': 2}, 'l': [{'k1': {'k1.1': 'v1.1*', 'k1.2': 'v1.2'}}, None, None, 3]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment