【问题标题】:Compare 2 lists of dictionaries and add missing (non-matching) dicts from one list to the other比较 2 个字典列表并将缺失(不匹配)的字典从一个列表添加到另一个列表
【发布时间】:2018-10-25 02:59:24
【问题描述】:

我有一个字典,其中包含另一个字典列表作为其中一个键的值。 我需要遍历这个嵌套字典并将其与另一个字典列表进行比较。应该添加其他列表中尚未包含在此列表中的任何字典。字典的嵌套列表如下所示:

{
"rules": [
    {
        "name": "Rule 1",
        "severity": "High"
    },
    {
        "name": "Rule 2 ",
        "severity": "Medium"
    }],
"Account":11111,
"Name": "Test Account"
}

第二个字典如下:

[{
  "name": "Rule 2",
  "severity": "Medium"
},
{
  "name": "Rule 3",
  "severity": "low"
}]

所以规则 3 应该被添加到第一个字典的 "rules" 列表中,规则 2 被忽略。

我已经走到了这一步,但如果我继续沿着这条路走下去,逻辑就不起作用,并导致非常复杂的嵌套 if 语句。我的编程技能非常新手:

for k, v in bundle.items():
i = bundle["rules"] 
for entity in i:
    for key, value in entity.items():

【问题讨论】:

    标签: python python-3.x list dictionary comparison


    【解决方案1】:

    您可以先将现有规则转换为集合以进行高效查找:

    d = {
    "rules": [
        {
            "name": "Rule 1",
            "severity": "High"
        },
        {
            "name": "Rule 2",
            "severity": "Medium"
        }],
    "Account":11111,
    "Name": "Test Account"
    }
    new = [{ "name": "Rule 2", "severity": "Medium" }, { "name": "Rule 3", "severity": "low" }]
    set_d = set(tuple(r.items()) for r in d['rules'])
    for r in new:
        if tuple(r.items()) not in set_d:
            d['rules'].append(r)
    print(d)
    

    这个输出:

    {'rules': [{'name': 'Rule 1', 'severity': 'High'}, {'name': 'Rule 2', 'severity': 'Medium'}, {'name': 'Rule 3', 'severity': 'low'}], 'Account': 11111, 'Name': 'Test Account'}

    【讨论】:

    • 太棒了。太感谢了。我将假设相同的逻辑也适用于删除。只需将“not in”替换为“in”,而不是 append(r),而是 remove(r)。
    • 很高兴能提供帮助。是的,这确实是正确的评估。
    【解决方案2】:

    正如 blhsign 所建议的,您应该使用一个集合。这需要使您的规则成为可散列的类型。我建议namedtuple。然后,不要迭代项目,而是利用集合的性质为您带来好处:

    from collections import namedtuple
    
    d = {
    "rules": [
        {
            "name": "Rule 1",
            "severity": "High"
        },
        {
            "name": "Rule 2",
            "severity": "Medium"
        }],
    "Account":11111,
    "Name": "Test Account"
    }
    
    rule_tuple = namedtuple('Rule', ['name', 'severity'])
    d['rules'] = {rule_tuple(**rule) for rule in d['rules']}
    
    new_rules = [
        {
          "name": "Rule 2",
          "severity": "Medium"
        },
        {
          "name": "Rule 3",
          "severity": "low"
        }
    ]
    new_rules = {rule_tuple(**rule) for rule in new_rules}
    d['rules'] = d['rules'].union(new_rules)
    d
    

    输出:

    {'rules': {Rule(name='Rule 1', severity='High'),
      Rule(name='Rule 2', severity='Medium'),
      Rule(name='Rule 3', severity='low')},
     'Account': 11111,
     'Name': 'Test Account'}
    

    【讨论】:

      【解决方案3】:

      如果真正需要比较的唯一值是规则名称,那么您可以只派生当前规则名称的列表并在循环通过要测试的新规则时检查名称匹配。

      data = {
          "rules": [{"name": "Rule 1", "severity": "High"}, {"name": "Rule 2", "severity": "Medium"}],
          "Account": 11111,
          "Name": "Test Account"
          }
      
      test_rules = [{"name": "Rule 2", "severity": "Medium"}, {"name": "Rule 3", "severity": "Low"}]
      
      rules = data['rules']
      names = [r['name'] for r in rules]
      
      for rule in test_rules:
          if rule['name'] not in names:
              rules.append(rule)
      
      print(data)
      # OUTPUT
      # {
      #     'rules': [
      #         {'name': 'Rule 1', 'severity': 'High'},
      #         {'name': 'Rule 2', 'severity': 'Medium'},
      #         {'name': 'Rule 3', 'severity': 'Low'}
      #         ],
      #     'Account': 11111,
      #     'Name': 'Test Account'
      # }
      

      假设名称比较是基于您的数据集的全部内容,这种方法比转换为一组元组,然后在循环中将比较数据转换为元组要快一些。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-08
        • 2016-09-14
        • 1970-01-01
        • 2017-08-21
        • 2013-11-06
        • 2019-10-07
        相关资源
        最近更新 更多