2014-03-27 2 views
2

두 개의 사전이 있는데, 내가하려는 것은 약간 이상합니다. 기본적으로, 나는 그들을 합병하고 싶다. 그 정도로 간단합니다. 그러나 그것들은 사전의 계층 구조입니다. 사전에있는 항목 자체가 사전이고 두 항목 모두에 존재하는 경우 그 사전을 병합하기를 원합니다. 사전이 아니면 두 번째 사전의 값이 첫 번째 값의 값을 덮어 쓰게합니다. 뭔가 이런 식으로 :파이썬에서 사전의 병합 계층

a = {0: {0: "a"}, 
    1: [0, 1, 2]} 

b = {0: {1: "b"}, 
    1: [3, 4, 5]} 

Merge(a, b) 

#output: 
{0: {0: "a", 
    1: "b"}, 
1: [3, 4, 5]} 

의미가 있습니까? 키 "0"은 a와 b 모두에 사전을 포함하고 있기 때문에 사전을 병합했습니다. 그러나 두 번째 키의 경우에는 목록 이었으므로 그냥 덮어 썼습니다.

그래서 어떤 종류의 재귀 함수를 살펴 볼까요? 이 방법에 접근하는 방법을 잘 모르겠습니다.

감사합니다.

편집 : 나는 2.6.2과 2.7.3 모두에서 작동하는 기능을 필요

: 나는 하나 개의 매우 중요한 세부 사항을 언급하는 것을 잊었다.

+0

어떤 경우 다른 딕셔너리의 딕셔너리는 2' 한 딕셔너리의 목록은 '1'이고 '의 값 ? – thefourtheye

+0

일반적으로 나는 그것이 실제로 일어날 것이라고 생각하지 않지만, 그런 경우에, 나는 다른 사전의 값으로 덮어 쓴다고 생각합니다. –

답변

1

,

from copy import deepcopy 

def merge(a, b): 
    if isinstance(b, dict) and isinstance(a, dict): 
     a_and_b = a.viewkeys() & b.viewkeys() 
     every_key = a.viewkeys() | b.viewkeys() 
     return {k: merge(a[k], b[k]) if k in a_and_b else 
        deepcopy(a[k] if k in a else b[k]) for k in every_key} 
    return deepcopy(b) 

merge(a, b)의 반환 값은 개념적으로 a의 (깊이) 사본을 만드는 것과 같습니다 a.update(b)의 재귀 버전 실행


일부 중첩 된 예를 사용하여,

a = {0: {0: 'a'}, 
    1: [0, 1, 2], 
    2: [9, 9], 
    3: {'a': {1: 1, 2: 2}, 'b': [0, 1]}} 

b = {0: {1: 'b'}, 
    1: [3, 4, 5], 
    2: {22: 22, 33: 33}, 
    3: {'a': {2: 22, 3: 33}, 'b': [99, 88]}} 

merge(a, b) 생산,

{0: {0: 'a', 1: 'b'}, 
1: [3, 4, 5], 
2: {22: 22, 33: 33}, 
3: {'a': {1: 1, 2: 22, 3: 33}, 'b': [99, 88]}} 

편집 : 파이썬 2.6 버전

def merge(a, b): 
    if isinstance(b, dict) and isinstance(a, dict): 
     a_and_b = set(a).intersection(b) 
     every_key = set(a).union(b) 
     return dict((k, merge(a[k], b[k]) if k in a_and_b else 
        deepcopy(a[k] if k in a else b[k])) for k in every_key) 
    return deepcopy(b) 
+0

그 덕분에, 고마워! –

+0

Errr, 빠른 질문 : Python 2.6.2에서이 작업을 시도 할 때 구문 오류가 발생합니다. 내가 2.6.2와 2.7.3에서 이것을 실행할 필요가 있다는 것을 잊어 버렸습니다. 나는이 코드에서 2.6.2 이후에 추가 된 것이 있다고 생각합니까? –

+0

맞아요, 그래서 첫 번째 "return"문장은 사전 이해력을 사용합니까? 아마 루프를 대신 할 수 있으며, 2.6.2에서 정상적으로 작동해야합니다. 덜 우아하지만 헤이. –

0

음 ... 임의로 중첩되지 않는 한 재귀가 필요하지 않습니다.

from itertools import chain 

{k:(v if not isinstance(v,dict) else dict(chain(a[k].items(), v.items()))) for k,v in b.items()} 
Out[10]: {0: {0: 'a', 1: 'b'}, 1: [3, 4, 5]} 

이 dicts을 병합하는 비열한 방법은 항상있다,이 조금 장황하기 때문에

(I는 파이썬에서 .iteritems와 2 .items을 대체 주시기 여기 파이썬 3를 사용하고 있습니다) :

{k:(v if not isinstance(v,dict) else dict(a[k], **v)) for k,v in b.items()} 
Out[11]: {0: {0: 'a', 1: 'b'}, 1: [3, 4, 5]} 

이 구문을 사용하고 싶을 수도 있고 사용하지 않을 수도 있습니다. 이는 작지만 간혹 cPython 구현 세부 사항입니다. 당신이이 같은 일을해야 (재귀의 관점에서 당신의 생각에 따라) 중첩 된 사전이있을 수 있습니다 가정

0

비슷한 것을 필요로하고 좀 더 간단한 재귀 적 솔루션을 구현했습니다. 적절한 업데이트 dict 'd'.

from Collections import MutableMapping 

def merge(d, v): 
    """ 
    Merge two dictionaries. 

    Merge dict-like `v` into dict-like `d`. In case keys between them are the same, merge 
    their sub-dictionaries where possible. Otherwise, values in `v` overwrite `d`. 
    """ 
    for key in v: 
     if key in d and isinstance(d[key], MutableMapping) and isinstance(v[key], MutableMapping): 
      d[key] = merge(d[key], v[key]) 
     else: 
      d[key] = v[key] 
    return d 

예 1

a = {0: {0: "a"}, 
    1: [0, 1, 2]} 

b = {0: {1: "b"}, 
    1: [3, 4, 5]} 

>>> merge(a, b) 
{0: {0: 'a', 1: 'b'}, 1: [3, 4, 5]} 

예 2

a = {0: {0: 'a'}, 
    1: [0, 1, 2], 
    2: [9, 9], 
    3: {'a': {1: 1, 2: 2}, 'b': [0, 1]}} 

b = {0: {1: 'b'}, 
    1: [3, 4, 5], 
    2: {22: 22, 33: 33}, 
    3: {'a': {2: 22, 3: 33}, 'b': [99, 88]}} 

>>> merge(a, b) 
{0: {0: 'a', 1: 'b'}, 
1: [3, 4, 5], 
2: {22: 22, 33: 33}, 
3: {'a': {1: 1, 2: 22, 3: 33}, 'b': [99, 88]}} 
관련 문제