[PYTHON] 다양한 깊이의 중첩 된 사전 값 업데이트
PYTHON다양한 깊이의 중첩 된 사전 값 업데이트
나는 dict dictionary1을 dict 업데이트의 내용으로 업데이트하는 방법을 찾고있다. levelA를 덮어 쓰지 않는다.
dictionary1={'level1':{'level2':{'levelA':0,'levelB':1}}}
update={'level1':{'level2':{'levelB':10}}}
dictionary1.update(update)
print dictionary1
{'level1': {'level2': {'levelB': 10}}}
가장 낮은 키 level1을 업데이트하기 때문에 update2가 level2의 값을 삭제한다는 것을 알고 있습니다.
dictionary1과 update가 길이를 가질 수 있다면 어떻게해야합니까?
해결법
-
==============================
1.@ FM의 대답은 재귀 적 솔루션 인 올바른 일반 아이디어를 가지고 있지만 다소 특이한 코딩과 적어도 하나의 버그가 있습니다. 대신 권하고 싶습니다.
@ FM의 대답은 재귀 적 솔루션 인 올바른 일반 아이디어를 가지고 있지만 다소 특이한 코딩과 적어도 하나의 버그가 있습니다. 대신 권하고 싶습니다.
파이썬 2 :
import collections def update(d, u): for k, v in u.iteritems(): if isinstance(v, collections.Mapping): d[k] = update(d.get(k, {}), v) else: d[k] = v return d
파이썬 3 :
import collections def update(d, u): for k, v in u.items(): if isinstance(v, collections.Mapping): d[k] = update(d.get(k, {}), v) else: d[k] = v return d
버그는 "업데이트"에 ak가있을 때 나타납니다. v 항목은 v가 사전이고 k가 원래 사전에있는 키가 아닙니다. @ FM의 코드는 업데이트의이 부분을 "건너 뜁니다" 저장되지 않거나 어디에서나 반환되는 빈 새 dict, 재귀 호출이 반환 될 때 손실 됨).
내 다른 변경 사항은 중요하지 않습니다 .get이 동일한 작업을 더 빠르고 깨끗하게 수행 할 때 if / else 구문을 사용할 이유가 없으며 isinstance가 일반 기본 클래스 (구체적이 아닌)에 가장 잘 적용됩니다.
-
==============================
2.이 점에 대해 조금 생각했지만, @ Alex의 덕분에 그는 내가 누락 된 틈을 메웠다. 그러나 반복적 인 dict 내의 값이 목록 일 경우 문제가 발생하여 공유하고 응답을 연장한다고 생각했습니다.
이 점에 대해 조금 생각했지만, @ Alex의 덕분에 그는 내가 누락 된 틈을 메웠다. 그러나 반복적 인 dict 내의 값이 목록 일 경우 문제가 발생하여 공유하고 응답을 연장한다고 생각했습니다.
import collections def update(orig_dict, new_dict): for key, val in new_dict.iteritems(): if isinstance(val, collections.Mapping): tmp = update(orig_dict.get(key, { }), val) orig_dict[key] = tmp elif isinstance(val, list): orig_dict[key] = (orig_dict.get(key, []) + val) else: orig_dict[key] = new_dict[key] return orig_dict
-
==============================
3.@ Alex의 답은 좋지만 update ({ 'foo': 0}, { 'foo': { 'bar': 1}})와 같은 정수로 요소를 대체 할 때는 작동하지 않습니다. 이 업데이트는이 문제를 해결합니다.
@ Alex의 답은 좋지만 update ({ 'foo': 0}, { 'foo': { 'bar': 1}})와 같은 정수로 요소를 대체 할 때는 작동하지 않습니다. 이 업데이트는이 문제를 해결합니다.
import collections def update(d, u): for k, v in u.iteritems(): if isinstance(d, collections.Mapping): if isinstance(v, collections.Mapping): r = update(d.get(k, {}), v) d[k] = r else: d[k] = u[k] else: d = {k: u[k]} return d update({'k1': 1}, {'k1': {'k2': {'k3': 3}}})
-
==============================
4.깊이가 다른 사전을 업데이트하고 업데이트가 원래 중첩 된 사전으로 잠수하는 깊이를 제한하는 @ Alex의 대답에 대한 사소한 개선 (업데이트 사전 깊이는 제한되지 않음). 몇 가지 경우 만 테스트되었습니다.
깊이가 다른 사전을 업데이트하고 업데이트가 원래 중첩 된 사전으로 잠수하는 깊이를 제한하는 @ Alex의 대답에 대한 사소한 개선 (업데이트 사전 깊이는 제한되지 않음). 몇 가지 경우 만 테스트되었습니다.
def update(d, u, depth=-1): """ Recursively merge or update dict-like objects. >>> update({'k1': {'k2': 2}}, {'k1': {'k2': {'k3': 3}}, 'k4': 4}) {'k1': {'k2': {'k3': 3}}, 'k4': 4} """ for k, v in u.iteritems(): if isinstance(v, Mapping) and not depth == 0: r = update(d.get(k, {}), v, depth=max(depth - 1, -1)) d[k] = r elif isinstance(d, Mapping): d[k] = u[k] else: d = {k: u[k]} return d
-
==============================
5.허용 된 솔루션과 동일한 솔루션이지만 더 명확한 변수 명명 인 docstring을 사용하고 값으로 {}가 무시되지 않는 버그가 수정되었습니다.
허용 된 솔루션과 동일한 솔루션이지만 더 명확한 변수 명명 인 docstring을 사용하고 값으로 {}가 무시되지 않는 버그가 수정되었습니다.
import collections def deep_update(source, overrides): """Update a nested dictionary or similar mapping. Modify ``source`` in place. """ for key, value in overrides.iteritems(): if isinstance(value, collections.Mapping) and value: returned = deep_update(source.get(key, {}), value) source[key] = returned else: source[key] = overrides[key] return source
다음은 몇 가지 테스트 사례입니다.
def test_deep_update(): source = {'hello1': 1} overrides = {'hello2': 2} deep_update(source, overrides) assert source == {'hello1': 1, 'hello2': 2} source = {'hello': 'to_override'} overrides = {'hello': 'over'} deep_update(source, overrides) assert source == {'hello': 'over'} source = {'hello': {'value': 'to_override', 'no_change': 1}} overrides = {'hello': {'value': 'over'}} deep_update(source, overrides) assert source == {'hello': {'value': 'over', 'no_change': 1}} source = {'hello': {'value': 'to_override', 'no_change': 1}} overrides = {'hello': {'value': {}}} deep_update(source, overrides) assert source == {'hello': {'value': {}, 'no_change': 1}} source = {'hello': {'value': {}, 'no_change': 1}} overrides = {'hello': {'value': 2}} deep_update(source, overrides) assert source == {'hello': {'value': 2, 'no_change': 1}}
이 함수는 charlatan 패키지의 charlatan.utils에서 사용할 수 있습니다.
-
==============================
6.아무도 그것을 필요로하는 경우에 대비하여 재귀 사전 병합의 불변 버전이 있습니다.
아무도 그것을 필요로하는 경우에 대비하여 재귀 사전 병합의 불변 버전이 있습니다.
@Alex Martelli의 답을 바탕으로합니다.
Python 2.x :
import collections from copy import deepcopy def merge(dict1, dict2): ''' Return a new dictionary by merging two dictionaries recursively. ''' result = deepcopy(dict1) for key, value in dict2.iteritems(): if isinstance(value, collections.Mapping): result[key] = merge(result.get(key, {}), value) else: result[key] = deepcopy(dict2[key]) return result
Python 3.x :
import collections from copy import deepcopy def merge(dict1, dict2): ''' Return a new dictionary by merging two dictionaries recursively. ''' result = deepcopy(dict1) for key, value in dict2.items(): if isinstance(value, collections.Mapping): result[key] = merge(result.get(key, {}), value) else: result[key] = deepcopy(dict2[key]) return result
-
==============================
7.이 두 가지 대답 중 어느 것도 저자는 사전에 저장된 객체를 업데이트하는 개념을 이해하지 못하는 것 같고 사전 항목을 반복하는 개념 (키가 아닌)을 이해하는 것처럼 보입니다. 그래서 무의미한 동사 사전 저장소와 검색을하지 않는 것을 작성해야했습니다. dicts는 다른 dicts 또는 단순한 유형을 저장하는 것으로 가정합니다.
이 두 가지 대답 중 어느 것도 저자는 사전에 저장된 객체를 업데이트하는 개념을 이해하지 못하는 것 같고 사전 항목을 반복하는 개념 (키가 아닌)을 이해하는 것처럼 보입니다. 그래서 무의미한 동사 사전 저장소와 검색을하지 않는 것을 작성해야했습니다. dicts는 다른 dicts 또는 단순한 유형을 저장하는 것으로 가정합니다.
def update_nested_dict(d, other): for k, v in other.items(): if isinstance(v, collections.Mapping): d_v = d.get(k) if isinstance(d_v, collections.Mapping): update_nested_dict(d_v, v) else: d[k] = v.copy() else: d[k] = v
또는 더 단순한 유형으로 작업하는 경우도 있습니다.
def update_nested_dict(d, other): for k, v in other.items(): d_v = d.get(k) if isinstance(v, collections.Mapping) and isinstance(d_v, collections.Mapping): update_nested_dict(d_v, v) else: d[k] = deepcopy(v) # or d[k] = v if you know what you're doing
-
==============================
8.솔루션을 더욱 강력하게 만들기 위해 @Alex Martelli의 답변을 업데이트하여 코드의 버그를 수정하십시오.
솔루션을 더욱 강력하게 만들기 위해 @Alex Martelli의 답변을 업데이트하여 코드의 버그를 수정하십시오.
def update_dict(d, u): for k, v in u.items(): if isinstance(v, collections.Mapping): default = v.copy() default.clear() r = update_dict(d.get(k, default), v) d[k] = r else: d[k] = v return d
핵심은 재귀에서 동일한 유형을 만들고 싶기 때문에 v.copy (). clear ()를 사용하지만 {}을 사용하지 않습니다. 여기에있는 dict가 다른 종류의 default_factory를 가질 수있는 collections.defaultdict 유형 인 경우 특히 유용합니다.
또한 u.iteritems ()가 Python3에서 u.items ()로 변경되었습니다.
-
==============================
9.@Alex Martelli가 제안한 해결책을 사용했지만 실패했습니다.
@Alex Martelli가 제안한 해결책을 사용했지만 실패했습니다.
TypeError 'bool'객체가 항목 할당을 지원하지 않습니다.
두 사전이 어느 정도 수준에서 데이터 유형이 다른 경우.
사전 d의 요소가 스칼라 (예 : Bool) 인 반면, 같은 레벨에서 사전 u의 요소는 여전히 사전이지만 사전 할당은 True (k)와 같이 스칼라에 사전 할당이 불가능하므로 사전 할당이 실패합니다.
하나의 조건을 추가하면 다음과 같이 수정됩니다.
from collections import Mapping def update_deep(d, u): for k, v in u.items(): # this condition handles the problem if not isinstance(d, Mapping): d = u elif isinstance(v, Mapping): r = update_deep(d.get(k, {}), v) d[k] = r else: d[k] = u[k] return d
-
==============================
10.iteritems-Attribute가없는 나 같은 비표준 사전에 비틀 거릴 수 있습니다. 이 경우이 유형의 사전을 표준 사전으로 쉽게 해석 할 수 있습니다. 예 :
iteritems-Attribute가없는 나 같은 비표준 사전에 비틀 거릴 수 있습니다. 이 경우이 유형의 사전을 표준 사전으로 쉽게 해석 할 수 있습니다. 예 :
import collections def update(orig_dict, new_dict): for key, val in dict(new_dict).iteritems(): if isinstance(val, collections.Mapping): tmp = update(orig_dict.get(key, { }), val) orig_dict[key] = tmp elif isinstance(val, list): orig_dict[key] = (orig_dict[key] + val) else: orig_dict[key] = new_dict[key] return orig_dict import multiprocessing d=multiprocessing.Manager().dict({'sample':'data'}) u={'other': 1234} x=update(d, u) x.items()
-
==============================
11.이 질문은 오래되었지만 "깊은 병합"솔루션을 검색 할 때 여기에 착륙했습니다. 위의 대답은 다음에 영감을주었습니다. 내가 테스트 한 모든 버전에 버그가 있었기 때문에 나는 내 자신의 글을 쓰게되었다. 놓친 중요한 점은 두 입력 dict의 임의의 깊이에서 어떤 키 k에 대해 d [k] 또는 u [k]가 dict가 아닌 결정 트리가 잘못되었음을 나타냅니다.
이 질문은 오래되었지만 "깊은 병합"솔루션을 검색 할 때 여기에 착륙했습니다. 위의 대답은 다음에 영감을주었습니다. 내가 테스트 한 모든 버전에 버그가 있었기 때문에 나는 내 자신의 글을 쓰게되었다. 놓친 중요한 점은 두 입력 dict의 임의의 깊이에서 어떤 키 k에 대해 d [k] 또는 u [k]가 dict가 아닌 결정 트리가 잘못되었음을 나타냅니다.
또한이 솔루션은 dict.update ()가 작동하는 방식과 더 대칭 인 재귀를 필요로하지 않으며 None을 반환합니다.
import collections def deep_merge(d, u): """Do a deep merge of one dict into another. This will update d with values in u, but will not delete keys in d not found in u at some arbitrary depth of d. That is, u is deeply merged into d. Args - d, u: dicts Note: this is destructive to d, but not u. Returns: None """ stack = [(d,u)] while stack: d,u = stack.pop(0) for k,v in u.items(): if not isinstance(v, collections.Mapping): # u[k] is not a dict, nothing to merge, so just set it, # regardless if d[k] *was* a dict d[k] = v else: # note: u[k] is a dict # get d[k], defaulting to a dict, if it doesn't previously # exist dv = d.setdefault(k, {}) if not isinstance(dv, collections.Mapping): # d[k] is not a dict, so just set it to u[k], # overriding whatever it was d[k] = v else: # both d[k] and u[k] are dicts, push them on the stack # to merge stack.append((dv, v))
-
==============================
12.그건 약간 편이지만 중첩 된 사전이 정말로 필요한가요? 문제에 따라 때로는 평면 사전만으로도 충분할 수 있습니다.
그건 약간 편이지만 중첩 된 사전이 정말로 필요한가요? 문제에 따라 때로는 평면 사전만으로도 충분할 수 있습니다.
>>> dict1 = {('level1','level2','levelA'): 0} >>> dict1['level1','level2','levelB'] = 1 >>> update = {('level1','level2','levelB'): 10} >>> dict1.update(update) >>> print dict1 {('level1', 'level2', 'levelB'): 10, ('level1', 'level2', 'levelA'): 0}
from https://stackoverflow.com/questions/3232943/update-value-of-a-nested-dictionary-of-varying-depth by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] sys.stdout.flush () 메서드 사용 (0) | 2018.10.03 |
---|---|
[PYTHON] 바이너리 실행 파일로 파이썬 스크립트를 컴파일하는 법 (0) | 2018.10.03 |
[PYTHON] 컴파일 된 .pyc 파일을 .py 파일로 디 컴파일 할 수 있습니까? (0) | 2018.10.03 |
[PYTHON] Google App Engine에서 파일 업로드 (0) | 2018.10.03 |
[PYTHON] 네트워크 연결 확인 중 (0) | 2018.10.03 |