Я пытаюсь написать собственный метод фильтрации, который принимает произвольное количество kwargs и возвращает список, содержащий элементы списка, подобного базе данных, которые содержат эти kwargs .
Например, предположим, что d1 = {'a':'2', 'b':'3'}
и d2
= одно и то же. d1 == d2
приводит к True. Но предположим d2
= то же самое плюс кучу других вещей. Мой метод должен иметь возможность определять, находится ли d1 в d2 , но Python не может этого сделать со словарями.
Контекст:
У меня есть класс слово, и каждый объект имеет свойства , такие как word
, definition
, part_of_speech
и так далее. Я хочу иметь возможность вызывать метод фильтрации по основному списку этих слов, например Word.objects.filter(word='jump', part_of_speech='verb-intransitive')
. Я не могу понять, как управлять этими ключами и значениями одновременно. Но это могло бы иметь более широкую функциональность вне этого контекста для других людей.
источник
d1.viewitems() <= d2.viewitems()
. Запуск Timeit показал более чем трехкратное улучшение производительности. Если не хэшируемый, даже использованиеiteritems()
вместоitems()
приводит к увеличению примерно в 1,2 раза. Это было сделано с использованием Python 2.7.items()
будет возвращать облегченные представления вместо копий. Никакой дальнейшей оптимизации не требуется.В Python 3 вы можете использовать,
dict.items()
чтобы получить набор элементов dict. Затем вы можете использовать<=
оператор, чтобы проверить, является ли одно представление "подмножеством" другого:В Python 2.7 используйте,
dict.viewitems()
чтобы сделать то же самое:В Python 2.6 и ниже вам понадобится другое решение, например
all()
:источник
d1.items() <= d2.items()
d1.items() <= d2.items()
они фактически сравнивают 2 списка кортежей без определенного порядка, поэтому конечный результат, вероятно, будет ненадежным. По этой причине я перехожу на ответ @blubberdiblub.d1.items() <= d2.items()
неопределенное поведение. Это не задокументировано в официальных документах и, что наиболее важно, не проверено: github.com/python/cpython/blob/… Так что это зависит от реализации.collections.abc.Set
, доступны все операции, определенные для абстрактного базового класса »Примечание для людей, которым это нужно для модульного тестирования:
assertDictContainsSubset()
вTestCase
классе Python также есть метод .http://docs.python.org/2/library/unittest.html?highlight=assertdictcontainssubset#unittest.TestCase.assertDictContainsSubset
Однако он устарел в версии 3.2, не знаю почему, возможно, для него есть замена.
источник
для проверки ключей и значений используйте:
set(d1.items()).issubset(set(d2.items()))
если нужно проверить только ключи:
set(d1).issubset(set(d2))
источник
d1={'a':1,'b':2}; d2={'a':2,'b':1}
-> второй фрагмент вернетсяTrue
...{'a', 'b'}
на самом деле является подмножеством{'a', 'b'}
;)Для полноты картины также можно сделать так:
Однако я не делаю никаких заявлений относительно скорости (или ее отсутствия) или читаемости (или ее отсутствия).
источник
small.viewitems() <= big.viewitems()
было многообещающим, но с одним предостережением: если ваша программа также может использоваться на Python 2.6 (или даже ниже),d1.items() <= d2.items()
они фактически сравнивают 2 списка кортежей без определенного порядка, поэтому окончательный результат, вероятно, будет ненадежный. По этой причине я переключаюсь на ответ @blubberdiblub. Проголосовали.dict
базовый класс? Что, если этого не произошло и он все еще ведет себя какdict
? Что, еслиsmall
иbig
содержат значения другого типа в соответствующем ключе, которые по-прежнему ведут себя как dict?False
когда значения переданных dicts разные для совпадающих ключей). Другими словами: решение для вложенных dicts не обязательно является заменой в зависимости от варианта использования.контекст:
источник
Моя функция для той же цели, делаю это рекурсивно:
В вашем примере
dictMatch(d1, d2)
должен возвращать True, даже если в d2 есть другие вещи, плюс это применимо также к более низким уровням:Примечания: Может быть даже лучшее решение, которое избегает этого
if type(pvalue) is dict
предложения и применяется к еще более широкому кругу случаев (например, спискам хэшей и т. Д.). Также рекурсия здесь не ограничена, поэтому используйте ее на свой страх и риск. ;)источник
Вот решение, которое также правильно рекурсивно перестраивается в списки и наборы, содержащиеся в словаре. Вы также можете использовать это для списков, содержащих dicts и т. Д.
источник
Эта, казалось бы, простая проблема стоит мне пару часов на поиск 100% надежного решения, поэтому я задокументировал то, что нашел в этом ответе.
Говоря «Pythonic-ally»,
small_dict <= big_dict
было бы наиболее интуитивно понятным способом, но жаль, что он не сработает .{'a': 1} < {'a': 1, 'b': 2}
вроде бы работает в Python 2, но это ненадежно, потому что это явно указано в официальном документе. Перейти к поиску «Результаты, отличные от равенства, решаются последовательно, но иначе не определяются». в этом разделе . Не говоря уже о том, что сравнение двух диктовок в Python 3 приводит к исключению TypeError.Вторая наиболее интуитивно понятная вещь - только
small.viewitems() <= big.viewitems()
для Python 2.7 иsmall.items() <= big.items()
для Python 3. Но есть одно предостережение: он потенциально содержит ошибки . Если ваша программа потенциально может быть использована на Python <= 2.6, наd1.items() <= d2.items()
самом деле она сравнивает 2 списка кортежей без определенного порядка, поэтому конечный результат будет ненадежным и станет неприятной ошибкой в вашей программе. Я не хочу писать еще одну реализацию для Python <= 2.6, но мне все еще неудобно, что в моем коде есть известная ошибка (даже если она на неподдерживаемой платформе). Поэтому я отказываюсь от этого подхода.Я согласен с ответом @blubberdiblub (заслуга ему):
def is_subdict(small, big): return dict(big, **small) == big
Стоит отметить, что этот ответ основан на
==
поведении между dicts, которое четко определено в официальном документе и, следовательно, должно работать в каждой версии Python . Искать:источник
Вот общее рекурсивное решение данной проблемы:
ПРИМЕЧАНИЕ. Исходный код в некоторых случаях не работает, за исправление следует @ olivier-melançon.
источник
if not set(value) <= set(superset[key])
Если вы не против использования,
pydash
естьis_match
то, что делает именно это:источник
Я знаю, что этот вопрос старый, но вот мое решение для проверки, является ли один вложенный словарь частью другого вложенного словаря. Решение рекурсивное.
источник
Эта функция работает для нехешируемых значений. Я также считаю, что это понятно и легко читается.
источник
Краткая рекурсивная реализация, которая работает для вложенных словарей:
Это потребует диктовки a и b. Если кто-нибудь знает хороший способ избежать этого, не прибегая к частично итеративным решениям, как в других ответах, скажите мне. Мне понадобится способ разбить диктант на голову и хвост на основе ключа.
Этот код более полезен в качестве упражнения по программированию и, вероятно, намного медленнее, чем другие решения здесь, которые сочетают рекурсию и итерацию. Решение @ Nutcracker неплохо подходит для вложенных словарей.
источник
a
(и к любому последующему первому значению)popitem
. Следует также изучить другие предметы на том же уровне. У меня есть пары вложенных dicts, где он возвращает неправильный ответ. (трудно представить здесь перспективный пример, поскольку он основан на порядкеpopitem
)Используйте этот объект-оболочку, который обеспечивает частичное сравнение и приятные различия:
источник