Подтвердить что ты не робот

Сравните словари, игнорируя определенные ключи

Как я могу проверить, являются ли два словаря равными при снятии некоторых ключей. Например,

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: Я ищу эффективное, быстрое решение.

UPD2. Я закончил с этим кодом, который кажется самым быстрым:

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

4b9b3361

Ответ 1

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

EDIT: это может быть быстрее и экономичнее:

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

Ответ 2

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

Ответ 3

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

Чем быстрее и чище! Обновление: набор бросков (игнорировать)

Ответ 4

Очень грубо, вы можете просто удалить любые игнорируемые ключи и сравнить эти словари:

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_

(Обратите внимание, что здесь нам не нужна глубокая копия, нам просто нужно избегать модификации d1 и d2.)

Ответ 5

Оптимальное решение для случая игнорирования только одного ключа

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