2017-02-14 3 views
3

にネストされた辞書の2レベルを合計Iは、同様のキー、それぞれ定義は異なる値を有する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つの辞書の構造が同じであることは保証されていますか? –

答えて

2

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

非常にありがとう、ウィレム、それは私の問題をより複雑な状態で解決しています。 – Faizalprbw

+0

@Faizalprbw:しかし、答えはこれが構造が同一である場合にのみ動作すると言います。したがって、両方の辞書は '2010'と' –

+1

はい、私は理解しています、実際には、上記のような同様のキーを持つ同じ構造を含む2つのjsonデータを持っています。 – Faizalprbw

1

別の解決策:) また、同じforループにdata1data2の両方を取得するためにzipを使用し、各dictsの値を追加するためにcollections.Counterを使用することができます。

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と同様の方法を使用することができますdictのサブクラスであるため。上記から

+0

'k1'は' k2'と異なる可能性があるので、これは必ずしも機能しません。 **これらのキーは、辞書では** **の順序ではありません。ただし、 'dict2'でルックアップを行うとうまくいきます。 –

+0

あなたの発言は間違っています、 'zip'は常に辞書の同じ' keys'を繰り返します。あるいは、あなたが言ったことを誤解したかもしれません。簡単な例を教えてください。あなたの解決策も良いですが、問題はそれらの間に連結するための 'n'辞書があるところにあります。 –

+0

ちょうど追加したいのは、 'zip'は2つの辞書の同じ' keys'を繰り返します。もしそれらが共通で 'keys'を共有している場合にのみ、それが機能しません。 –

1

あなたは辞書を追加する場合()最大Chrétiens'素敵なショートソリューションには、あなたが通常の辞書で終わるだろうが:

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

両方の辞書がまったく同じを共有する場合、これは、しかし、唯一の正しく動作しますキーを使用することができます。 Willem Van Onsemのソリューションは、両方の辞書で共有されていないキーがある場合は機能しません(エラーが発生しますが、MaxChrétiensのソリューションはこの場合誤ってアイテムをマージします)。今度は、同じ構造のキーを持つJSONデータを使用していると言いましたので、問題はありません。MaxChrétienのソリューションはうまくいくはずです。

両方のディクショナリ(およびそのサブディクショナリ)で共有されているキーだけが使用されていることを確認したい場合は、次のように動作します。 "X"をどのように追加しましたか:111111を2012サブディクショナリと "1999"のキー値ペアとして:{'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:あなたのソリューションはどんな状況にも適応しているように見えますが、キーが同じときにn個の辞書をマージできる関数を作ることができればいいと思います。また、両方のdict(たとえあなたの ''X':111111')でもない場合でも、他の値を追加してください。 –

+0

上記のforループと条件付きフレンジーバージョンを追加しました。しかし、これまでのところ最もエレガントなソリューションであると思われるものについては、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

これは素晴らしいです!ある辞書にはキーがあり、もう一方の辞書にはキーがないと機能しません。さらに、1つのサブキー(ネストされた辞書のキー、すなわち、外部辞書の値である辞書)が両方の辞書によって共有されない場合にも機能する。テストしたすべてのケースをカバーしているようです。 :-) –