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

Испытание, если dict содержится в dict

Тестирование на равенство работает отлично, как это для python dicts:

first  = {"one":"un", "two":"deux", "three":"trois"}
second = {"one":"un", "two":"deux", "three":"trois"}

print(first == second) # Result: True

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

first  = {"one":"un", "two":"deux", "three":"trois"}
second = {"one":"un", "two":"deux", "three":"trois", "foo":"bar"}

Есть ли простой способ проверить, является ли первый dict частью второго dict, со всеми его ключами и значениями?

РЕДАКТИРОВАТЬ 1:

Этот вопрос, как предполагается, является дубликатом Как проверить, содержит ли словарь определенные ключи, но я заинтересован в тестировании ключей и их значений. Просто содержащие одни и те же ключи не делают два диктофона равными.

ИЗМЕНИТЬ 2:

ОК, теперь я получил несколько ответов, используя четыре разных метода, и доказал, что все они работают. Поскольку мне нужен быстрый процесс, я тестировал каждый для времени выполнения. Я создал три идентичных dicts с 1000 элементами, ключи и значения были случайными строками длиной 10. В second и third были добавлены дополнительные пары ключ-значение, а последний не-дополнительный ключ third получил новый стоимость. Итак, first является подмножеством second, но не third. Используя модуль timeit с 10000 повторениями, я получил:

Method                                                      Time [s]   
first.viewitems() <=second.viewitems()                           0.9 
set(first.items()).issubset(second.items())                      7.3
len(set(first.items()) & set(second.items())) == len(first)      8.5
all(first[key] == second.get(key, sentinel) for key in first)    6.0

Я догадался, что последний метод является самым медленным, но он находится на месте 2. Но метод 1 превосходит их всех.

Спасибо за ваши ответы!

4b9b3361

Ответ 1

Вы можете использовать словарь словарь:

# Python 2
if first.viewitems() <= second.viewitems():
    # true only if `first` is a subset of `second`

# Python 3
if first.items() <= second.items():
    # true only if `first` is a subset of `second`

Словарь - это стандарт в Python 3, в Python 2 вам нужно приписать стандартные методы с помощью view. Они действуют как наборы, а <= проверяет, является ли одно из них подмножеством (или равно) другим.

Демо в Python 3:

>>> first  = {"one":"un", "two":"deux", "three":"trois"}
>>> second = {"one":"un", "two":"deux", "three":"trois", "foo":"bar"}
>>> first.items() <= second.items()
True
>>> first['four'] =  'quatre'
>>> first.items() <= second.items()
False

Это также работает и для недопустимых значений, поскольку ключи делают пары ключ-значение уникальными. Документация немного запутанна в этом вопросе, но даже с изменяемыми значениями (скажем, списками) это работает:

>>> first_mutable = {'one': ['un', 'een', 'einz'], 'two': ['deux', 'twee', 'zwei']}
>>> second_mutable = {'one': ['un', 'een', 'einz'], 'two': ['deux', 'twee', 'zwei'], 'three': ['trois', 'drie', 'drei']}
>>> first_mutable.items() <= second_mutable.items()
True
>>> first_mutable['one'].append('ichi')
>>> first_mutable.items() <= second_mutable.items()
False

Вы также можете использовать функцию all() с выражением генератора; используйте object() как часовое для краткого определения недостающих значений:

sentinel = object()
if all(first[key] == second.get(key, sentinel) for key in first):
    # true only if `first` is a subset of `second`

но это не так читаемо и выразительно, как использование словарных представлений.

Ответ 2

all(k in second and second[k] == v for k, v in first.items())

если вы знаете, что ни одно из значений не может быть None, оно упростит:

all(second.get(k, None) == v for k, v in first.items())

Ответ 3

Итак, вы в основном хотите проверить, является ли один словарь подмножеством другого.

first  = {"one":"un", "two":"deux", "three":"trois"}
second = {"one":"un", "two":"deux", "three":"trois", "foo":"bar"}

def subset_dic(subset, superset):
    return len(set(subset.items()) & set(superset.items())) == len(subset)


print(subset_dic(first, second))

Отпечатки:

True

Если вы хотите абстрагировать часть подмножества/надмножества:

def subset_dic(dict1, dict2):
    return len(set(dict1.items()) & set(dict2.items())) == len(min((dict1, dict2), key=len))

Примечание: это не сработает, если какое-либо значение является изменчивым объектом. Следовательно, вы можете добавить дополнительный шаг (преобразовать изменяемый объект в неизменяемый аналог) в функцию, чтобы преодолеть это ограничение.

Ответ 4

# Обновлено:

МЕТОД-1: Использование словарных представлений:

Как Martijn, мы можем использовать словарные представления, чтобы проверить это. dict.viewitems() действует как набор. Мы можем выполнять различные операции над этим, например, пересечение, объединение и т.д. (Проверьте ссылка.)

first.viewitems() <= second.viewitems()
True

Проверяем, меньше ли first second. Это значение, равное True, означает first - подмножество second.

МЕТОД-2 Использование функции issubset() для наборов:

(ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: этот метод имеет некоторую избыточность и требует, чтобы все значения были хешируемыми. Предлагается метод-1 для обработки всех случаев. Спасибо Martijn для предложений.)

Используйте атрибут .items() словаря для получения списка кортежей (ключ, значение), а затем используйте issubset() работу наборов.

Это будет проверять как ключи, так и равенство..

>>> first  = {"one":"un", "two":"deux", "three":"trois"}
>>> second = {"one":"un", "two":"deux", "three":"trois", "foo":"bar"}

>>> set(first.items()).issubset(second.items())
True