2016-04-29 11 views
2

2つの辞書を比較しようとしています。目的は、以前にどのキーが存在していたのか(失われていない)、一致するキー内でどのような値が変更されたかを調べることです(変更済み)辞書をループしてキー深度をトラッキングする

私は疑似作業スクリプトを持っていますが、変更されたキーと値のペアが属するキー

import json 
from pprint import pprint 

def new_keys(d1, d2, result={}): 
    for key in d1.keys(): 
     if not d2.has_key(key): 
      result[key] = d1[key] 
     else: 
      if isinstance(d1[key], dict) and isinstance(d2[key], dict): 
       new_keys(d1[key], d2[key], result) 
      else: 
       if d1[key] != d2[key]: 
        result[key] = d2[key] 

    return result 

with open("before.json") as data_file: 
    before = json.loads(data_file.read()) 

with open("after.json") as data_file: 
    after = json.loads(data_file.read()) 

pprint(new_keys(before,after)) 

現在の結果は以下のとおりです。

{u'1.1.1.1/32': {u'directlyConnected': True, 
       u'hardwareProgrammed': True, 
       u'kernelProgrammed': True, 
       u'routeAction': u'drop', 
       u'routeType': u'static', 
       u'vias': []}, 

私が欲しいの例の結果は次のとおりです。(それは別のルート0.0.0.0/0の代わりに、1.1.1.1/32です)それがネストされていることに気付きますvrfs内では、デフォルト、ルートキー。

{u'vrfs': {u'default': {u'allRoutesProgrammedHardware': True, 
         u'allRoutesProgrammedKernel': True, 
         u'defaultRouteState': u'reachable', 
         u'routes': {u'0.0.0.0/0': {u'directlyConnected': False, 
                u'hardwareProgrammed': True, 
                u'kernelProgrammed': True, 
                u'metric': 0, 
                u'preference': 1, 
                u'routeAction': u'forward', 
                u'routeType': u'static', 
                u'vias': [{u'interface': u'Management1', 
                   u'nexthopAddr': u'10.31.32.1'}]}, 

私は深いステップが、私はそれを適切にコード化困難を抱えていると何とかキーを追跡する必要があると思います。

ご協力いただきありがとうございます。

EDIT:例JSON

​​

後 - インタフェースの値が変更された

{ 
    "vrfs": { 
     "default": { 
      "routes": { 
       "2.2.2.2/32": { 
        "kernelProgrammed": true, 
        "directlyConnected": true, 
        "routeAction": "forward", 
        "vias": [ 
         { 
          "interface": "Ethernet9" 
         } 
        ], 
        "hardwareProgrammed": true, 
        "routeType": "static" 
       } 
      }, 
      "allRoutesProgrammedKernel": true, 
      "routingDisabled": false, 
      "allRoutesProgrammedHardware": true, 
      "defaultRouteState": "reachable" 
     } 
    } 
} 

+0

得るものです。ですから、 'new_keys()'を呼び出すたびに、新しい 'result' dictを渡して、その値を呼び出し元の繰り返しに格納する必要があります。 jsonの前後にサンプルを投稿できる場合は – WreckeR

+0

@WreckeR前後のサンプルjsonデータを追加しました。これは私の最初のpythonスクリプトなので、あなたのポイントを説明するサンプルコードを表示することができれば、それは非常に感謝しています。 – exilent

答えて

0

ここに私のコメントに基づいて考えられる解決策があります。また、いくつかのpythonic改善。 iteritems()key not in dictを使用してください。あなたのサンプルと

import json 
from pprint import pprint 

def new_keys(d1, d2, result={}): 
    for key, d1_val in d1.iteritems(): 
     if key not in d2: 
      result[key] = d1_val 
     else: 
      if isinstance(d1_val, dict) and isinstance(d2[key], dict): 
       # Don't pass result. 
       new_result = {} 
       new_keys(d1[key], d2[key], new_result) 
       # If new_result is not empty 
       if new_result: 
        result[key] = new_result 
      else: 
       if d1_val != d2[key]: 
        result[key] = d1_val 

    return result 

with open("before.json") as data_file: 
    before = json.loads(data_file.read()) 

with open("after.json") as data_file: 
    after = json.loads(data_file.read()) 
pprint(new_keys(before,after)) 

JSONの前と後のこれはあなたがネストされた辞書をしたいので、あなたの周りに同じ `result`辞書を渡すべきではありません、私は

{u'vrfs': {u'default': {u'routes': {u'2.2.2.2/32': {u'vias': [{u'interface': u'Ethernet4'}]}}}}} 
+0

この例の再帰がどのように機能し、深さを適切に追跡するかはわかりません。 – exilent

+0

私は何が間違っているのか分かりませんが、おそらくペーストミスですが、私は別の出力を得ていました。 – exilent

+0

ここでのキーは 'new_result'です。再帰の任意のポイントnew_resultが空でない場合、ツリー上のすべてのパスは空でない 'new_result'になります – WreckeR