【问题标题】:Looping through a dictionary and tracking key depth遍历字典并跟踪关键深度
【发布时间】:2016-08-24 21:02:45
【问题描述】:

我希望比较两个字典。目标是找出之前存在哪些键,但之后不存在(丢失),以及在匹配键中更改了哪些值(已更改)

我有一个伪工作脚本,但问题是它没有显示更改后的键/值对所属的所有键。

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'}]},

我怀疑随着我的深入,我需要以某种方式跟踪密钥,但我很难正确编码。

非常感谢任何帮助!

编辑:示例 JSON

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

之后 -

{
    "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"
        }
    }
}

接口值改变了。

【问题讨论】:

  • 既然你想要嵌套字典,你不应该传递相同的result 字典。因此,对于每次调用 new_keys(),您都应该传入一个新的 result dict,然后将值存储在调用者迭代中。如果您可以在 json 之前和之前发布示例可能会有所帮助
  • @WreckeR 我已经为之前/之后添加了示例 json 数据。这是我的第一个 python 脚本,所以如果您能向我展示示例代码来解释您的观点,将不胜感激。

标签: python json python-2.7 loops dictionary


【解决方案1】:

根据我上面的评论,这是一个可能的解决方案。还有一些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 之前和之后使用您的示例,这就是我得到的

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

【讨论】:

  • 我看不出这个例子中的递归将如何工作并适当地跟踪深度。
  • 不确定我做错了什么,可能是粘贴错误,但我得到了不同的输出。
  • 这里的关键是new_result。如果递归中的任何点 new_result 不为空,则树上的每条路径现在都有一个非空的 new_result
  • 我在看到您的示例后更新了我的代码。此外,我必须明确地将一个空的result 传递给循环中对new_keys() 的每个调用。
  • 感谢 Wrecker。这很棒。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-27
  • 2015-10-25
  • 1970-01-01
  • 1970-01-01
  • 2014-05-04
  • 1970-01-01
相关资源
最近更新 更多