Próbuję napisać niestandardową metodę filtru, która pobiera dowolną liczbę kwarg i zwraca listę zawierającą elementy listy podobnej do bazy danych, która zawiera te kwargi .
Na przykład załóżmy, że d1 = {'a':'2', 'b':'3'}
i d2
= to samo. d1 == d2
wyniki w True. Ale przypuśćmy, że d2
= to samo plus kilka innych rzeczy. Moja metoda musi być w stanie stwierdzić, czy d1 w d2 , ale Python nie może tego zrobić ze słownikami.
Kontekst:
Mam klasy słowo, a każdy obiekt ma właściwości takie jak word
, definition
, part_of_speech
i tak dalej. Chcę mieć możliwość wywołania metody filtrującej na głównej liście tych słów, na przykład Word.objects.filter(word='jump', part_of_speech='verb-intransitive')
. Nie mogę dowiedzieć się, jak jednocześnie zarządzać tymi kluczami i wartościami. Ale może to mieć większą funkcjonalność poza tym kontekstem dla innych ludzi.
źródło
d1.viewitems() <= d2.viewitems()
. Testy Timeit wykazały ponad 3-krotną poprawę wydajności. Jeśli nie można haszować, nawet użycieiteritems()
zamiastitems()
prowadzi do około 1,2-krotnej poprawy. Dokonano tego za pomocą Pythona 2.7.items()
zwróci lekkie widoki zamiast kopii. Nie jest wymagana dalsza optymalizacja.W Pythonie 3 możesz użyć,
dict.items()
aby uzyskać podobny do zestawu widok elementów dict. Następnie możesz użyć<=
operatora, aby sprawdzić, czy jeden widok jest „podzbiorem” drugiego:W Pythonie 2.7 użyj,
dict.viewitems()
aby zrobić to samo:W Pythonie 2.6 i starszych będziesz potrzebować innego rozwiązania, takiego jak użycie
all()
:źródło
d1.items() <= d2.items()
d1.items() <= d2.items()
faktycznie porównują 2 listy krotek, bez określonej kolejności, więc ostateczny wynik prawdopodobnie nie będzie wiarygodny. Z tego powodu przełączam się na odpowiedź @blubberdiblub.d1.items() <= d2.items()
jest niezdefiniowanym zachowaniem. Nie jest to udokumentowane w oficjalnej dokumentacji i, co najważniejsze, nie jest to testowane: github.com/python/cpython/blob/… Więc to zależy od implementacji.collections.abc.Set
dostępne są wszystkie operacje zdefiniowane dla abstrakcyjnej klasy bazowej ”Uwaga dla osób, które potrzebują tego do testów jednostkowych:
assertDictContainsSubset()
wTestCase
klasie Pythona jest również metoda .http://docs.python.org/2/library/unittest.html?highlight=assertdictcontainssubset#unittest.TestCase.assertDictContainsSubset
Jest jednak przestarzały w wersji 3.2, nie wiem dlaczego, może jest dla niego zamiennik.
źródło
do sprawdzania kluczy i wartości użyj:
set(d1.items()).issubset(set(d2.items()))
jeśli chcesz sprawdzić tylko klucze:
set(d1).issubset(set(d2))
źródło
d1={'a':1,'b':2}; d2={'a':2,'b':1}
-> drugi fragment powróciTrue
...{'a', 'b'}
jest w rzeczywistości podzbiorem{'a', 'b'}
;)Aby uzyskać kompletność, możesz również zrobić to:
Jednak nie składam żadnych roszczeń dotyczących szybkości (lub jej braku) lub czytelności (lub jej braku).
źródło
small.viewitems() <= big.viewitems()
były obiecujące, ale z jednym zastrzeżeniem: jeśli twój program może być również używany w Pythonie 2.6 (lub nawet poniżej), wd1.items() <= d2.items()
rzeczywistości porównują 2 listy krotek, bez określonej kolejności, więc ostateczny wynik prawdopodobnie nie wiarygodny. Z tego powodu przełączam się na odpowiedź @blubberdiblub. Głosowano za.dict
klasę bazową? A jeśli tak nie jest i nadal zachowuje się jakdict
? Co jeślismall
ibig
zawierają wartości innego typu w pasującym kluczu, który nadal zachowuje się jak dict?False
wartościami przekazanych nakazów są różne dla pasujących kluczy). Innymi słowy: rozwiązanie dla zagnieżdżonych dykt niekoniecznie jest zastępstwem typu drop-in w zależności od przypadku użycia.kontekst:
źródło
Moja funkcja w tym samym celu, robiąc to rekurencyjnie:
W twoim przykładzie
dictMatch(d1, d2)
powinno zwrócić True, nawet jeśli d2 zawiera inne rzeczy, a ponadto ma to zastosowanie również do niższych poziomów:Uwagi: Mogłoby być jeszcze lepsze rozwiązanie, które pozwala uniknąć
if type(pvalue) is dict
klauzuli i ma zastosowanie do jeszcze szerszego zakresu przypadków (takich jak listy skrótów itp.). Rekurencja nie jest tutaj ograniczona, więc korzystaj z niej na własne ryzyko. ;)źródło
Oto rozwiązanie, które również poprawnie powraca do list i zestawów zawartych w słowniku. Możesz również użyć tego do list zawierających dykty itp ...
źródło
Ten pozornie prosty problem kosztuje mnie kilka godzin w poszukiwaniu w 100% niezawodnego rozwiązania, więc udokumentowałem to, co znalazłem w tej odpowiedzi.
Mówienie „sojusznik Pythona”
small_dict <= big_dict
byłoby najbardziej intuicyjnym sposobem, ale szkoda, że nie zadziała .{'a': 1} < {'a': 1, 'b': 2}
pozornie działa w Pythonie 2, ale nie jest wiarygodny, ponieważ oficjalna dokumentacja wyraźnie to określa. Przejdź do wyszukiwania „Wyniki inne niż równość są rozwiązywane konsekwentnie, ale nie są zdefiniowane w inny sposób”. w tej sekcji . Nie wspominając o tym, że porównanie 2 dykt w Pythonie 3 powoduje wyjątek TypeError.Druga najbardziej intuicyjna rzecz dotyczy
small.viewitems() <= big.viewitems()
tylko Pythona 2.7 ismall.items() <= big.items()
Pythona 3. Jest jednak jedno zastrzeżenie: potencjalnie zawiera błędy . Jeśli twój program mógłby potencjalnie być użyty w Pythonie <= 2.6,d1.items() <= d2.items()
to faktycznie porównuje 2 listy krotek, bez określonej kolejności, więc ostateczny wynik będzie niewiarygodny i stanie się paskudnym błędem w twoim programie. Nie mam ochoty pisać kolejnej implementacji dla Pythona <= 2.6, ale nadal nie czuję się komfortowo, że mój kod zawiera znany błąd (nawet jeśli jest na nieobsługiwanej platformie). Dlatego porzucam to podejście.Zgadzam się z odpowiedzią @blubberdiblub (zasługa go):
def is_subdict(small, big): return dict(big, **small) == big
Warto zaznaczyć, że ta odpowiedź opiera się na
==
zachowaniu między dyktami, które jest jasno zdefiniowane w oficjalnym dokumencie, stąd powinno działać w każdej wersji Pythona . Szukaj:źródło
Oto ogólne rekurencyjne rozwiązanie podanego problemu:
UWAGA: W niektórych przypadkach oryginalny kod zawodzi, a kredyty za naprawienie trafiają do @ olivier-melançon
źródło
if not set(value) <= set(superset[key])
Jeśli nie masz nic przeciwko używaniu
pydash
, jestis_match
tam, który dokładnie to robi:źródło
Wiem, że to pytanie jest stare, ale oto moje rozwiązanie umożliwiające sprawdzenie, czy jeden słownik zagnieżdżony jest częścią innego słownika zagnieżdżonego. Rozwiązanie jest rekurencyjne.
źródło
Ta funkcja działa dla wartości, których nie można mieszać. Myślę też, że jest przejrzysty i łatwy do odczytania.
źródło
Krótka rekurencyjna implementacja, która działa dla zagnieżdżonych słowników:
Spowoduje to zużycie dykt a i b. Jeśli ktoś zna dobry sposób na uniknięcie tego bez uciekania się do częściowo iteracyjnych rozwiązań, jak w innych odpowiedziach, proszę, powiedz mi. Potrzebowałbym sposobu na podzielenie dyktu na głowę i ogon na podstawie klucza.
Ten kod jest bardziej przydatny jako ćwiczenie programistyczne i prawdopodobnie jest dużo wolniejszy niż inne rozwiązania tutaj, które łączą rekurencję i iterację. Rozwiązanie @ Dziadek do orzechów jest całkiem dobre dla zagnieżdżonych słowników.
źródło
a
(i każdą kolejną pierwszą wartość)popitem
znalezionych. Powinien również zbadać inne elementy na tym samym poziomie. Mam pary zagnieżdżonych poleceń, w których zwraca nieprawidłową odpowiedź. (trudno tu przedstawić przykład przyszłościowy, ponieważ opiera się on na kolejnościpopitem
)Użyj tego obiektu opakowującego, który zapewnia częściowe porównanie i ładne różnice:
źródło