Испытание, если 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 превосходит их всех.
Спасибо за ваши ответы!
Ответы
Ответ 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