Python 如何递归地遍历两个字典,并基于另一个字典修改原始字典?

Python 如何递归地遍历两个字典,并基于另一个字典修改原始字典?,python,algorithm,dictionary,recursion,Python,Algorithm,Dictionary,Recursion,我正在尝试遍历一个字典(它有许多字符串、dict、dict列表),并将其与另一个字典进行比较 下面是一个例子: data = { "topic": "Seniors' Health Care Freedom Act of 2007", "foo": "bar", "last_update": "2011-08-29T20:47:44Z", "organ

我正在尝试遍历一个字典(它有许多字符串、dict、dict列表),并将其与另一个字典进行比较

下面是一个例子:

data = {
  "topic": "Seniors' Health Care Freedom Act of 2007",
  "foo": "bar",
  "last_update": "2011-08-29T20:47:44Z",
  "organisations": [
    {
      "organization_id": "22973",
      "name": "National Health Federation",
      "bar": "baz"
    },
    {
      "organization_id": "27059",
      "name": "A Christian Perspective on Health Issues"
    },
]}

validate = {
  "topic": None,
  "last_update": "next_update",
  "organisations": [
      {
        "organization_id": None,
        "name": None
      }
    ]
}
基本上,如果项目存在于“数据”中,但在当前点不存在于“验证”中,则应将其从数据中删除

因此,在本例中,我希望数据[“foo”]和数据[“organizations”][x][“bar”]从数据目录中删除

此外,如果validate中的键有一个字符串值并且不是“None”,我想将数据中的键名更新为该值,即“last_update”应该变成“next_update”

我不确定在Python中有什么好方法可以做到这一点,我当前的版本删除了“foo”,但我正在努力删除嵌套键,比如[x][bar]

这是我目前的尝试:

def func1(data, validate, parent = None):
  for k, v in sorted(data.items()):
    if not parent:
      if k not in validate:
        data.pop(k, None)

    if isinstance(v, dict):
        func1(v, validate)
    elif isinstance(v, list):
      for val in v:
          func1(val, validate, parent = k)

func1(data, validate)
我尝试使用类似这样的方法来比较键,但我认为如果数据中有额外的键(似乎删除了错误的键),则效果不好,因为dict是未排序的,因此对我没有用处:

for (k, v), (k2, v2) in zip(sorted(data.items()), sorted(validate.items())):

我读过类似的文章,比如,但这似乎使用了一个平面集进行过滤,因此它没有考虑到dict中键的位置,这对我来说很重要,因为“last_update”可以出现在我需要保留它的其他列表中。

这里是一个简单的递归函数。嗯,过去很简单,;然后我添加了大量的检查,现在这是一个if森林

def验证数据(数据,验证):
对于输入列表(data.keys()):
如果密钥不在验证中:
del数据[键]
elif validate[key]不是无:
如果存在(数据[键],dict):
验证数据(数据[键]、验证[键])
elif isinstance(数据[键],列表):
对于子数据,在zip中进行子验证(数据[key],验证[key]):
如果isinstance(子数据,dict)和isinstance(子验证,dict):
验证数据(子数据,子验证)
其他:
数据[键]=验证[键]
它的工作原理:如果
data[key]
是一个字典,并且
key
是有效的,那么我们要对照
data[key]
中的键检查
data[key]
中的键。所以我们做了一个递归调用,但不是在递归调用中放入
validate
,而是放入
validate[key]
。同样,如果
数据[key]
是一个列表

假设:如果
data
中的一个列表包含非字典的元素,或者当
data[key]
存在但不是字典或无字典时
data[key]
是字典,或者当
validate[key]存在时
data[key]
是列表,则上述代码将失败
存在,但不是列表或无

关于if林的重要注意事项:if/else/if/elif/else的顺序很重要。特别是,我们只在没有列表的情况下执行
data[key]=validate[key]
。如果
validate[key]
是一个列表,那么
data[key]=validate[key]
将导致
data[key]
成为同一个列表,而不是列表的副本,这肯定不是您想要的


关于
列表(data.keys())
的重要注意事项:
我使用迭代
作为输入列表(data.keys()):
而不是
作为输入数据:
作为输入键,数据中的值:
。通常这不是迭代dict的首选方式。但是我们在for循环中使用
del
从字典中删除值,这会干扰迭代。因此,我们需要在删除任何元素之前获得键列表,然后使用该列表进行迭代。

有趣的问题!为了防止大量的
if…else…
,您需要找到一种允许递归的方法,而不管传入值的类型如何

因此,我认为您需要以下规则:

  • 如果
    数据
    中的任何值在
    验证
    中为无,则应保留
    数据
    中的值
  • 如果
    数据
    验证
    中的值是字典,则仅保留
    数据
    中的键(如果也存在于
    验证
    中),并将这些规则递归应用于其他键
  • 如果
    数据
    验证
    中的值是列表,则仅保留
    数据
    中的项目(如果也存在于
    验证
    中),并将这些规则递归应用于其他项目
  • 如果
    数据
    中的任何值在
    验证
    中不为无且规则(2)和(3)不适用,则
    数据
    中的值应替换为
    验证
  • 以下是我的建议:

    def消毒(数据1、数据2): “”“根据*数据2清理*数据1*。”* """ #如果value2为None,只需返回value1即可 如果数据2为无: 返回数据1 #如果两个值都是字典,则递归更新value1。 elif isinstance(数据1,dict)和isinstance(数据2,dict): 返回{ 键:清理(_值,data2.get(键)) 对于键,\ data1.items()中的值 如果输入数据2 } #如果两个值都是列表,则递归更新value1。 elif isinstance(数据1,列表)和isinstance(数据2,列表): 返回[ 清理(子值1、子值2) 对于子值1,子值2 在zip中(数据1、数据2) ] #否则,只需返回value2。 返回数据2 使用您的值,您将获得以下输出:

    >清理(数据、验证)
    {
    “主题”:2007年《老年人保健自由法》,
    “上次更新”:“下次更新”,
    ‘机构’:[
    {
    “组织id”:“22973”,
    “名称”:“国家卫生联盟”
    }
    ]
    }
    
    根据规则3,我假设如果
    validate
    中不存在,您希望从
    data
    中删除所有列表项,因此删除第二个I