【问题标题】:Is there a better way to compare dictionary values有没有更好的方法来比较字典值
【发布时间】:2009-12-15 23:39:12
【问题描述】:

我目前正在使用以下函数来比较字典值并显示所有不匹配的值。有更快或更好的方法吗?

match = True
for keys in dict1:
    if dict1[keys] != dict2[keys]:
        match = False
        print keys
        print dict1[keys],
        print  '->' ,
        print dict2[keys]

编辑:两个字典都包含相同的键。

【问题讨论】:

  • 需要澄清一下...您是否要确定 dict1 和 dict2 是否包含完全相同的内容?或者 dict2 是否可以包含其他不在 dict1 中的值?另外,您是否需要能够显示所有不匹配的键?
  • 我需要能够显示所有不匹配的值。 dict2 与 dict1 具有相同的键
  • 这就是我要写的内容。可以print dict1[keys], "->", dict2[keys]一行。
  • 这是一个可视化差异的工具:github.com/AJamesPhillips/compare/tree/master

标签: python dictionary


【解决方案1】:

如果问题的真正意图是字典之间的比较(而不是打印差异),那么答案是

dict1 == dict2

这在之前已经提到过,但我觉得它有点淹没在其他信息中。可能看起来很表面,但dicts的值比较实际上具有强大的语义。它涵盖了

  • 键的数量(如果它们不匹配,则字典不相等)
  • 键名(如果不匹配,则不相等)
  • 每个键的值(它们也必须是 '==')

最后一点再次显得微不足道,但非常有趣,因为这意味着所有这些递归地应用也适用于嵌套字典。例如

 m1 = {'f':True}
 m2 = {'f':True}
 m3 = {'a':1, 2:2, 3:m1}
 m4 = {'a':1, 2:2, 3:m2}
 m3 == m4  # True

列表比较存在类似的语义。所有这一切使得它变得不费吹灰之力。比较深层 Json 结构,仅使用简单的“==”。

【讨论】:

  • all of this applies recursively to nested dicts as well 这是否明确记录,以及对复杂嵌套结构的任何限制,例如dict等列表的dict?
  • 我想不出有一篇关于这个的文档。我的答案来自经验和实验。我向您推荐相同的,例如测试您感兴趣的一些数据结构的比较。
  • 哇,这是真的 - == 进行深度比较,至少对于基本类型!在 REPL 中尝试:a = {"a": False, 'b':[1,2,{'foo':'bar','zamboni':True,'cheese':[False,[]]},3],'c':None}; b = {'c':None, 'a': False, 'b':[1,2,{'cheese':[False,[]],'foo':'bar','zamboni':True},3]}; a == b。酷!
  • 我也没有找到applies recursively to nested dicts as well部分的官方文档,但是,对于它的价值,last sentence of this section中正式承诺了==两个dicts的相等比较,还有你可以在 separated section 中搜索“映射(dict 的实例)比较相等”。
  • 如果每个元素都通过== 测试并且任何元素都可以是字典,那么它当然会递归地应用于嵌套字典。
【解决方案2】:

如果 dicts 具有相同的键集,并且您需要所有这些打印来获得任何值差异,那么您无能为力;可能是这样的:

diffkeys = [k for k in dict1 if dict1[k] != dict2[k]]
for k in diffkeys:
  print k, ':', dict1[k], '->', dict2[k]

几乎等同于您所拥有的,但您可能会获得更好的演示文稿,例如通过在循环之前对差异键进行排序。

【讨论】:

  • 使用dict2.get(k) 更安全,因为它可能不存在。此外,如果您想真正比较这两种方式,您可能想要反过来做,因为它只会从 dict1 键的角度检测,例如。当 dict2 有更多的属性时
【解决方案3】:

你也可以使用套装

>>> a = {'x': 1, 'y': 2}
>>> b = {'y': 2, 'x': 1}
>>> set(a.iteritems())-set(b.iteritems())
set([])
>>> a['y']=3
>>> set(a.iteritems())-set(b.iteritems())
set([('y', 3)])
>>> set(b.iteritems())-set(a.iteritems())
set([('y', 2)])
>>> set(b.iteritems())^set(a.iteritems())
set([('y', 3), ('y', 2)])

【讨论】:

  • 这非常有效,除非其中一个值是不可散列的(例如,list)。 set({'x': []}.iteritems()) 将引发TypeError
  • @user212218 - 对于具有不可散列对象的字典项,请参见此处:stackoverflow.com/questions/43504568/…
【解决方案4】:

嗯,你在描述dict1 == dict2(检查两个字典是否相等)

但是您的代码所做的是all( dict1[k]==dict2[k] for k in dict1 )(检查 dict1 中的所有条目是否都等于 dict2 中的条目)

【讨论】:

  • 这错过了 dict2 在 dict1 上有 additional 键的情况,因此它们实际上的行为不同。
【解决方案5】:

不确定这是否有帮助,但在我的应用中,我必须检查字典是否已更改。

这样做是行不通的,因为基本上它仍然是同一个对象:

val={'A':1,'B':2}
old_val=val

val['A']=10
if old_val != val:
  print('changed')

使用复制/深复制作品:

import copy
val={'A':1,'B':2}
old_val=copy.deepcopy(val)

val['A']=10
if old_val != val:
  print('changed')

【讨论】:

    【解决方案6】:
    >>> a = {'x': 1, 'y': 2}
    >>> b = {'y': 2, 'x': 1}
    >>> print a == b
    True
    >>> c = {'z': 1}
    >>> print a == c
    False
    >>> 
    

    【讨论】:

      【解决方案7】:

      如果你只是比较平等,你可以这样做:

      if not dict1 == dict2:
          match = False
      

      否则,我看到的唯一主要问题是,如果 dict1 中有一个不在 dict2 中的键,你会得到一个 KeyError,所以你可能想做这样的事情:

      for key in dict1:
          if not key in dict2 or dict1[key] != dict2[key]:
              match = False
      

      你可以把它压缩成一个理解,只得到不匹配的键列表:

      mismatch_keys = [key for key in x if not key in y or x[key] != y[key]]
      match = not bool(mismatch_keys) #If the list is not empty, they don't match 
      for key in mismatch_keys:
          print key
          print '%s -> %s' % (dict1[key],dict2[key])
      

      我能想到的唯一其他优化可能是使用“len(dict)”来确定哪个 dict 的条目较少,然后首先循环遍历那个 dict 以获得最短的循环。

      【讨论】:

      • match = not (dict1 == dict2)?
      • @vinntec 不就是dict1 != dict2吗?
      • 我建议更多避免这种模式if condition then True else False。除此之外,根据语言和涉及的类型,有时not(==)!= 不一样,所以我只是要小心。
      【解决方案8】:

      如果您的值是可散列的(即字符串),那么您可以简单地比较两个字典的 ItemsView。

      https://docs.python.org/3/library/stdtypes.html#dict-views

      set_with_unique_key_value_pairs = dict1.items() ^ dict2.items()
      set_with_matching_key_value_pairs = dict1.items() & dict2.items()
      

      您可以使用任何set 操作。

      由于在这种情况下您可能不关心键,因此您也可以只使用 ValuesView(同样,前提是值是可散列的)。

      set_with_matching_values = dict1.values() & dict2.values()
      

      【讨论】:

        【解决方案9】:

        如果您的字典嵌套很深,并且它们包含不同类型的集合,您可以将它们转换为 json 字符串并进行比较。

        import json
        match = (json.dumps(dict1) == json.dumps(dict2))
        

        警告 - 如果您的字典在值中有二进制字符串,则此解决方案可能不起作用,因为这不是 json 可序列化的

        【讨论】:

        • 注意 -- 至少在 Python 2.6 中,不能保证顺序是一致的,因此如果键是相同的 key:values 在两个 dicts 中生成不同的 json.dumps() 是可能的以不同的顺序并由某些字符串组成。 (老实说,无法确定确切的规则,但在我的两个字典中,将比较两侧相同键中的前导“b”更改为“v”会导致结果字符串不同,可重复。)跨度>
        • 最好使用深度相等函数。它会更便宜并且实际上可以正常工作。
        • @DanD:你能详细说明在这种情况下什么是深度相等函数吗?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-22
        • 2013-05-23
        • 1970-01-01
        • 2017-05-20
        • 2016-07-21
        相关资源
        最近更新 更多