2017-02-14 1 views
3

에 중첩 된 사전의 2 레벨을 합산 나는 비슷한 키, 각 정의에 다른 값이 2 중첩 된 사전 변수가 : 내 경우파이썬

data1 = { 
"2010":{ 
     'A':2, 
     'B':3, 
     'C':5 
    }, 
"2011":{ 
     'A':1, 
     'B':2, 
     'C':3 
    }, 
"2012":{ 
     'A':1, 
     'B':2, 
     'C':4 
    } 
} 

data2 = { 
"2010":{ 
     'A':4, 
     'B':4, 
     'C':5 
    }, 
"2011":{ 
     'A':1, 
     'B':1, 
     'C':3 
    }, 
"2012":{ 
     'A':3, 
     'B':2, 
     'C':4 
    } 
} 

를, 나는 같은에 따라 두 사전의 값을 합산 할 필요가 키를 입력하면 대답은 다음과 같이됩니다.

data3 = { 
"2010":{ 
     'A':6, 
     'B':7, 
     'C':10 
    }, 
"2011":{ 
     'A':2, 
     'B':3, 
     'C':6 
    }, 
"2012":{ 
     'A':4, 
     'B':4, 
     'C':8 
    } 
} 

어떻게 할 수 있습니까?

+0

두 사전의 구조가 동일하게 보장 되나요? –

답변

2

두 사전의 구조가 동일 감안할 때, 당신은 그것을 위해 사전 이해를 사용할 수 있습니다

data3 = {key:{key2:val1+data2[key][key2] for key2,val1 in subdic.items()} for key,subdic in data1.items()} 

을 REPL에서 다음과 같이

>>> {key:{key2:val1+data2[key][key2] for key2,val1 in subdic.items()} for key,subdic in data1.items()} 
{'2010': {'B': 7, 'C': 10, 'A': 6}, '2012': {'B': 4, 'C': 8, 'A': 4}, '2011': {'B': 3, 'C': 6, 'A': 2}} 

독해력 작동 :에 바깥 쪽 루프는 key,subdic을 반복합니다. data1입니다. 따라서 귀하의 경우 key은 1 년이고 subdic은 해당 연도의 사전 (data1)입니다.

지금이 년의 각각에 대해, 우리는 subdic의 항목을 반복하고 여기 key2'A', 'B''C'입니다. val1은이 키들에 대해 data1에있는 값입니다. data2[key][key2]을 쿼리하여 다른 값을 얻습니다. 우리는 이것을 합하여 새로운 사전을 만듭니다.

+0

Willem 대단히 감사합니다. 복잡한 상황에서도 제 문제를 해결해줍니다. – Faizalprbw

+0

@Faizalprbw : 답변에 따르면 구조가 동일하면이 기능이 작동하므로 두 사전에 '2010'과 ' A ','B','C'를'2010' 등으로 변환합니다. –

+1

예, 사실 저는 위의 예제와 같이 비슷한 키를 가진 두 개의 json 데이터를 가지고 있습니다. – Faizalprbw

1

또 다른 방법 : 또한 각 dicts의 값을 추가 collections.Counter를 사용하여 다음 같은 for 루프에서 모두 data1data2를 얻을 수 zip를 사용하고 있습니다.

from collections import Counter 

>> {k1: Counter(v1) + Counter(v2) for (k1, v1), (k2, v2) in zip(sorted(data1.items()), sorted(data2.items()))} 
{'2011': Counter({'C': 6, 'B': 3, 'A': 2}), '2010': Counter({'C': 10, 'B': 7, 'A': 6}), '2012': Counter({'C': 8, 'A': 4, 'B': 4})} 

당신은 Counter 딕셔너리로 ​​종료되지만이 dict의 서브 클래스이기 때문에 당신은 여전히 ​​일반 dict과 같은 방법을 사용할 수 있습니다. 당신이 위에서 최대 Chrétiens '좋은 짧은 솔루션 DICT()를 추가하면

+0

'k1'은'k2'와 다를 수 있기 때문에 이것은 항상 작동하지 않습니다. ** 키는 ** 사전에 ** 정렬되어 있지 않습니다. 그러나 만약 당신이'dict2'에서 검색을하면 작동 할 것입니다. –

+0

당신의 말은 틀린데,'zip'은 항상 사전에있는'keys'를 반복합니다. 아니면 내가 네가 한 말을 오해했을 수도있다. 간단한 예제를 제공해 주시겠습니까? 당신의 솔루션은 훌륭하지만 문제는 그들 사이에 'n'사전이있는 곳을 낳습니다. –

+0

그냥 추가하고 싶다면,'zip'은 2 사전의 'keys'를 반복 할 것입니다. 그리고 공통적으로 'keys'가 공통적으로 _있는 경우에만 작동합니다. 그렇지 않으면 작동하지 않을 것입니다. –

1

, 당신은 정기적으로 사전에 종료됩니다 : 모두 사전 정확히 같은 공유하는 경우

data3 = {k1: dict(Counter(v1) + Counter(v2)) for (k1, v1), (k2, v2) in 
     zip(data1.items(), data2.items())} 

이 뜻은, 그러나, 제대로 작동 키를 사용합니다. Willem Van Onsem의 솔루션은 두 사전 모두에서 공유되지 않는 키가있는 경우 작동하지 않습니다 (Max Chrétiens의 솔루션은 항목을 잘못 병합하는 반면 오류가 발생합니다). 이제는 비슷한 구조의 키가있는 JSON 데이터를 사용한다고 언급 했으므로 문제가되지 않아야하며 Max Chrétien의 솔루션이 제대로 작동해야합니다.

두 사전 (및 해당 하위)에서 공유하는 키만 사용하려면 다음이 작동해야합니다. "X"를 어떻게 추가했는지 확인하십시오. 2012 년 하위 사전과 {1999 년}의 키 값 쌍인 111111 : 전체 하위 사전으로 { 'Z': 999999}.

def sum_two_nested_dicts(d1, d2): 
    dicts = [d1, d2] 
    d_sum = {} 
    for topkey in dicts[0]: 
     if topkey in dicts[1]: 
      d_sum[topkey] = {} 
      for key in dicts[0][topkey]: 
       if key in dicts[1][topkey]: 
        new_val = sum([d[topkey][key] for d in dicts]) 
        d_sum[topkey][key] = new_val 
    return d_sum 


data1 = { 
    "2010": { 
     'A': 2, 
     'B': 3, 
     'C': 5 
    }, 
    "2011": { 
     'A': 1, 
     'B': 2, 
     'C': 3 
    }, 
    "2012": { 
     'A': 1, 
     'B': 2, 
     'C': 4, 
     'X': 111111 
    }, 
    "1999": { 
     'Z': 999999 
    } 
} 

data2 = { 
    "2010": { 
     'A': 4, 
     'B': 4, 
     'C': 5 
    }, 
    "2011": { 
     'A': 1, 
     'B': 1, 
     'C': 3 
    }, 
    "2012": { 
     'A': 3, 
     'B': 2, 
     'C': 4 
    } 
} 

data3 = sum_two_nested_dicts(data1, data2) 

print(data3) 

# different order of arguments 

data4 = sum_two_nested_dicts(data2, data1) 

print(data4) 

# {'2010': {'C': 10, 'A': 6, 'B': 7}, '2012': {'C': 8, 'A': 4, 'B': 4}, '2011': {'C': 6, 'A': 2, 'B': 3}} 
# {'2010': {'C': 10, 'A': 6, 'B': 7}, '2012': {'C': 8, 'A': 4, 'B': 4}, '2011': {'C': 6, 'A': 2, 'B': 3}} 

나는 여기까지 할 수있는만큼 간결하고 우아한으로부터 실현,하지만 난 이미 어쨌든 그것을 쓴 경우 다른 사람이 특정 기능을 달성하기 위해 노력하고있다, 나는 여기를 게시 할 수 있습니다.보이는위한

def sum_nested_dicts(dic1, dic2): 
    # create list of both dictionaries 
    dicts = [dic1, dic2] 
    # create a set of all unique keys from both dictionaries 
    topkeys = set(sum([list(dic.keys()) for dic in dicts], [])) 
    # this is the merged dictionary to be returned 
    d_sum = {} 
    for topkey in topkeys: 
     # if topkey is shared by both dictionaries 
     if topkey in dic1 and topkey in dic2: 
      d_sum[topkey] = {} 
      keys = set(sum([list(dic[topkey].keys()) for dic in 
          dicts], [])) 
      for key in keys: 
       # if key is shared by both subdictionaries 
       if key in dic1[topkey] and key in dic2[topkey]: 
        new_val = sum([d[topkey][key] for d in dicts]) 
        d_sum[topkey][key] = new_val 
       # if key is only contained in one subdictionary 
       elif key in dic1[topkey]: 
        d_sum[topkey][key] = dic1[topkey][key] 
       elif key in dic2[topkey]: 
        d_sum[topkey][key] = dic2[topkey][key] 
     # if topkey is only contained in one dictionary 
     elif topkey in dic1: 
      d_sum[topkey] = dic1[topkey] 
     elif topkey in dic2: 
      d_sum[topkey] = dic2[topkey] 
    return d_sum 

참조 크리스탈의 솔루션 이미 쓴해서, 비공유 키/값을 유지

길고 부풀어 버전은 ... 지금까지 게시 된 가장 간결하고 기능적인 해결책이 될 수 있습니다.

+0

내 솔루션 업그레이드를위한 Thx : 귀하의 솔루션은 어떤 상황에도 적용되는 것처럼 보이지만 키가 동일 할 때 사전을 병합 할 수있는 기능을 만드는 것이 좋을 것 같습니다. 두 dict (예 : 'X': 111111')가 모두 같지 않더라도 다른 값을 추가하십시오. –

+0

위의 for-loop-and-if-condition-frenzy 버전을 추가했습니다. 지금까지 가장 우아한 해결책 인 Crystal 솔루션을보십시오. :) –

1

나는이 도움이 되었으면 좋겠 :

data1 = { "2010":{ 'A':2, 'B':3, 'C':5 }, "2011":{ 'A':1, 'B':2, 'C':3 }, "2012":{ 'A':1, 'B':2, 'C':4 } } 
    data2 = { "2010":{ 'A':4, 'B':4, 'C':5 }, "2011":{ 'A':1, 'B':1, 'C':3 }, "2012":{ 'A':3, 'B':2, 'C':4 } } 

    data3 = {} 

    for data in [data1,data2]: 
     for year in data.keys(): 
       for x,y in data[year].items(): 
        if not year in data3.keys(): 
         data3[year] = {x:y} 
        else: 
         if not x in data3[year].keys(): 
          data3[year].update({x:y}) 
         else: 
          data3[year].update({x:data3[year][x] + y}) 
    print data3 

이 내부 및 외부 사전의 임의의 길이에 대한 작동합니다.

+0

이것은 아주 좋습니다! 한 사전에는 키가 있고 다른 한 사전에는 키가있는 경우에도 작동합니다. 또한, 하나의 서브 키 (중첩 된 사전의 키, 즉 외부 사전의 값인 사전)가 두 사전에 의해 공유되지 않으면 작동 할 것이다. 테스트 한 모든 사례를 다루고있는 것 같습니다. :-) –