python 比较字典忽略特定键

fxnxkyjh  于 11个月前  发布在  Python
关注(0)|答案(9)|浏览(95)

如何在不考虑某些键的情况下测试两个字典是否相等。例如,

equal_dicts(
    {'foo':1, 'bar':2, 'x':55, 'y': 77 },
    {'foo':1, 'bar':2, 'x':66, 'z': 88 },
    ignore_keys=('x', 'y', 'z')
)

字符串
应该返回True。
UPD:我正在寻找一个高效、快速的解决方案。
2012.我最终得到了这段代码,它似乎是最快的:

def equal_dicts_1(a, b, ignore_keys):
    ka = set(a).difference(ignore_keys)
    kb = set(b).difference(ignore_keys)
    return ka == kb and all(a[k] == b[k] for k in ka)


计时:https://gist.github.com/2651872

wkftcu5l

wkftcu5l1#

def equal_dicts(d1, d2, ignore_keys):
    d1_filtered = {k:v for k,v in d1.items() if k not in ignore_keys}
    d2_filtered = {k:v for k,v in d2.items() if k not in ignore_keys}
    return d1_filtered == d2_filtered

字符串
编辑:这可能更快,更内存效率:

def equal_dicts(d1, d2, ignore_keys):
    ignored = set(ignore_keys)
    for k1, v1 in d1.iteritems():
        if k1 not in ignored and (k1 not in d2 or d2[k1] != v1):
            return False
    for k2, v2 in d2.iteritems():
        if k2 not in ignored and k2 not in d1:
            return False
    return True

igsr9ssn

igsr9ssn2#

使用dict解析:

>>> {k: v for k,v in d1.items() if k not in ignore_keys} == \
... {k: v for k,v in d2.items() if k not in ignore_keys}

字符串
在Python 2上使用.viewitems()

cl25kdpy

cl25kdpy3#

这是另一个变体:

set(ignore_keys).issuperset(k for (k, v) in d1.items() ^ d2.items())

字符串
它的优点:

  • C速度识别字典之间的差异
  • C快速检查被忽略的键集中的成员资格
  • 如果发现单个不匹配,则提前退出
sbdsn5lh

sbdsn5lh4#

如果你在测试时需要这个检查,你可以使用unittest.mock库中的ANY。下面是一个例子。

from unittest.mock import ANY
actual = {'userName':'bob', 'lastModified':'2012-01-01'}
expected = {'userName':'bob', 'lastModified': ANY}
assert actual == expected

字符串
See more

fhg3lkii

fhg3lkii5#

非常 * 非常 * 粗糙,你可以删除任何忽略的键并比较这些字典:

def equal_dicts(d1, d2, ignore_keys=()):
    d1_, d2_ = d1.copy(), d2.copy()
    for k in ignore_keys:
        try:
            del d1_[k]
        except KeyError: 
            pass
        try:
            del d2_[k]
        except KeyError: 
            pass

    return d1_ == d2_

字符串
(Note这里我们不需要一个深拷贝,我们只需要避免修改d1d2

hgtggwj0

hgtggwj06#

def compare_dict(d1, d2, ignore):
    for k in d1:
        if k in ignore:
            continue
        try:
            if d1[k] != d2[k]:
                return False
        except KeyError:
            return False
    return True

字符串
注解编辑:您可以执行类似compare_dict(d1, d2, ignore) and compare_dict(d2, d1, ignore)的操作或复制for

def compare_dict(d1, d2, ignore):
    ignore = set(ignore)
    for k in d1:
        if k in ignore:
            continue
        try:
            if d1[k] != d2[k]:
                return False
        except KeyError:
            return False

    for k in d2:
        if k in ignore:
            continue
        try:
            if d1[k] != d2[k]:
                return False
        except KeyError:
            return False
    return True


无论是更快和更干净!更新:铸造集(忽略)

0sgqnhkj

0sgqnhkj7#

如果我们知道两个字典有相同的键:

def equal_dicts(dic1: dict, dict2: dict, keys_to_ignore: set) -> bool:
    return all(dic1[key] == dict2[key] for key in dic1.keys() if key not in keys_to_ignore)

字符串
如果我们不知道两个字典有相同的键,如果dict2有一些dict1中缺少的不可忽略的键,那么上面的方法就会失败,所以我们可以改变方法来首先检查dict2没有任何额外的键:

def equal_dicts(dic1: dict, dict2: dict, keys_to_ignore: set) -> bool:
    return (
        all (key in dict1 for key in dic2.keys() if key not in keys_to_ignore)
        and all(dic1[key] == dict2[key] for key in dic1.keys() if key not in keys_to_ignore)
    )

but5z9lq

but5z9lq8#

只忽略一个密钥情况下的最优解

return all(
    (x == y or (x[1] == y[1] == 'key to ignore')) for x, y in itertools.izip(
          d1.iteritems(), d2.iteritems()))

字符串

jjhzyzn0

jjhzyzn09#

如果您的字典包含列表或其他字典:

def equal_dicts(d1, d2, ignore_keys, equal):
    # print('got d1', d1)
    # print('got d2', d2)
    if isinstance(d1, str):
        if not isinstance(d2, str):
            return False
        return d1 == d2
    for k in d1:
        if k in ignore_keys:
            continue
        if not isinstance(d1[k], dict) and not isinstance(d1[k], list) and d2.get(k) != d1[k]:
            print(k)
            equal = False
        elif isinstance(d1[k], list):
            if not isinstance(d2.get(k), list):
                equal = False
            if len(d1[k]) != len(d2[k]):
                return False
            if len(d1[k]) > 0 and isinstance(d1[k][0], dict):
                if not isinstance(d2[k][0], dict):
                    return False
                d1_sorted = sorted(d1[k], key=lambda item: item.get('created'))
                d2_sorted = sorted(d2[k], key=lambda item: item.get('created'))
                equal = all(equal_dicts(x, y, ignore_keys, equal) for x, y in zip(d1_sorted, d2_sorted)) and equal
            else:
                equal = all(equal_dicts(x, y, ignore_keys, equal) for x, y in zip(d1[k], d2[k])) and equal
        elif isinstance(d1[k], dict):
            if not isinstance(d2.get(k), dict):
                equal = False
            print(k)
            equal = equal_dicts(d1[k], d2[k], ignore_keys, equal) and equal
    return equal

字符串

相关问题