J'essaie d'écrire une méthode de filtrage personnalisée qui prend un nombre arbitraire de kwargs et renvoie une liste contenant les éléments d'une liste de type base de données qui contient ces kwargs .
Par exemple, supposons d1 = {'a':'2', 'b':'3'}
et d2
= la même chose. d1 == d2
donne True. Mais supposez d2
= la même chose plus un tas d'autres choses. Ma méthode doit être capable de dire si d1 dans d2 , mais Python ne peut pas le faire avec des dictionnaires.
Le contexte:
J'ai une classe Word, et chaque objet possède des propriétés comme word
, definition
, part_of_speech
et ainsi de suite. Je veux pouvoir appeler une méthode de filtrage sur la liste principale de ces mots, comme Word.objects.filter(word='jump', part_of_speech='verb-intransitive')
. Je n'arrive pas à comprendre comment gérer ces clés et ces valeurs en même temps. Mais cela pourrait avoir des fonctionnalités plus importantes en dehors de ce contexte pour d'autres personnes.
la source
d1.viewitems() <= d2.viewitems()
. Les exécutions Timeit ont montré une amélioration des performances de 3x. S'il n'est pas hachable, même utiliseriteritems()
au lieu deitems()
conduit à une amélioration d'environ 1,2x. Cela a été fait en utilisant Python 2.7.items()
renverra des vues légères au lieu de copies. Aucune optimisation supplémentaire n'est nécessaire.Dans Python 3, vous pouvez utiliser
dict.items()
pour obtenir une vue d'ensemble des éléments dict. Vous pouvez ensuite utiliser l'<=
opérateur pour tester si une vue est un "sous-ensemble" de l'autre:Dans Python 2.7, utilisez le
dict.viewitems()
pour faire de même:Dans Python 2.6 et les versions antérieures, vous aurez besoin d'une solution différente, telle que l'utilisation de
all()
:la source
d1.items() <= d2.items()
d1.items() <= d2.items()
ils comparent en fait 2 listes de tuples, sans ordre particulier, donc le résultat final ne sera probablement pas fiable. Pour cette raison, je passe à la réponse de @blubberdiblub.d1.items() <= d2.items()
est un comportement indéfini. Cela n'est pas documenté dans la documentation officielle et, le plus important, cela n'est pas testé: github.com/python/cpython/blob /... Cela dépend donc de l'implémentation.collections.abc.Set
sont disponibles"Remarque pour les personnes qui en ont besoin pour les tests unitaires: il existe également une
assertDictContainsSubset()
méthode dans laTestCase
classe de Python .http://docs.python.org/2/library/unittest.html?highlight=assertdictcontainssubset#unittest.TestCase.assertDictContainsSubset
Il est cependant obsolète dans la version 3.2, je ne sais pas pourquoi, il y a peut-être un remplacement.
la source
pour les clés et les valeurs, vérifiez l'utilisation:
set(d1.items()).issubset(set(d2.items()))
si vous devez vérifier uniquement les clés:
set(d1).issubset(set(d2))
la source
d1={'a':1,'b':2}; d2={'a':2,'b':1}
-> le deuxième extrait sera de retourTrue
...{'a', 'b'}
est en fait un sous-ensemble de{'a', 'b'}
;)Pour être complet, vous pouvez également faire ceci:
Cependant, je ne fais aucune réclamation concernant la vitesse (ou son absence) ou la lisibilité (ou son absence).
la source
small.viewitems() <= big.viewitems()
étaient prometteuses, mais avec une mise en garde: si votre programme pouvait également être utilisé sur Python 2.6 (ou même en dessous),d1.items() <= d2.items()
ils comparent en fait 2 listes de tuples, sans ordre particulier, donc le résultat final sera probablement pas fiable. Pour cette raison, je passe à la réponse de @blubberdiblub. J'ai voté pour.dict
comme classe de base? Et s'il ne l'a pas fait et se comporte toujours comme undict
? Que faire sismall
etbig
contenir des valeurs de type différent à une clé correspondante qui se comportent toujours comme dict?False
lorsque les valeurs des dictées passées sont différents pour les clés correspondantes). Ou en d'autres termes: la solution pour les dictionnaires imbriqués n'est pas nécessairement un remplacement instantané selon le cas d'utilisation.le contexte:
la source
Ma fonction dans le même but, en faisant cela de manière récursive:
Dans votre exemple,
dictMatch(d1, d2)
devrait retourner True même si d2 contient d'autres éléments, et cela s'applique également aux niveaux inférieurs:Notes: Il pourrait y avoir une solution encore meilleure qui évite la
if type(pvalue) is dict
clause et s'applique à un éventail encore plus large de cas (comme les listes de hachages, etc.). De plus, la récursivité n'est pas limitée ici, alors utilisez-la à vos propres risques. ;)la source
Voici une solution qui se répète également correctement dans les listes et les ensembles contenus dans le dictionnaire. Vous pouvez également l'utiliser pour les listes contenant des dictionnaires, etc.
la source
Ce problème apparemment simple me coûte quelques heures de recherche pour trouver une solution fiable à 100%, j'ai donc documenté ce que j'ai trouvé dans cette réponse.
Parler "allié pythonique"
small_dict <= big_dict
serait la manière la plus intuitive, mais dommage que cela ne fonctionne pas .{'a': 1} < {'a': 1, 'b': 2}
fonctionne apparemment dans Python 2, mais il n'est pas fiable car la documentation officielle le mentionne explicitement. Rechercher "Les résultats autres que l'égalité sont résolus de manière cohérente, mais ne sont pas définis autrement." dans cette section . Sans oublier, la comparaison de 2 dicts en Python 3 entraîne une exception TypeError.La deuxième chose la plus intuitive
small.viewitems() <= big.viewitems()
concerne uniquement Python 2.7 etsmall.items() <= big.items()
Python 3. Mais il y a une mise en garde: il est potentiellement bogué . Si votre programme peut potentiellement être utilisé sur Python <= 2.6, ild1.items() <= d2.items()
compare en fait 2 listes de tuples, sans ordre particulier, donc le résultat final ne sera pas fiable et cela deviendra un vilain bogue dans votre programme. Je n'ai pas envie d'écrire une autre implémentation pour Python <= 2.6, mais je ne me sens toujours pas à l'aise avec le fait que mon code soit livré avec un bogue connu (même s'il se trouve sur une plate-forme non prise en charge). J'abandonne donc cette approche.Je m'installe avec la réponse de @blubberdiblub (le mérite lui revient):
def is_subdict(small, big): return dict(big, **small) == big
Il convient de souligner que cette réponse repose sur le
==
comportement entre les dictionnaires, qui est clairement défini dans le document officiel, et devrait donc fonctionner dans toutes les versions de Python . Lancer la recherche:la source
Voici une solution récursive générale pour le problème donné:
REMARQUE: le code d'origine échouerait dans certains cas, le crédit pour la correction va à @ olivier-melançon
la source
if not set(value) <= set(superset[key])
Si cela ne vous dérange pas d'utiliser,
pydash
il y ais_match
là qui fait exactement cela:la source
Je sais que cette question est ancienne, mais voici ma solution pour vérifier si un dictionnaire imbriqué fait partie d'un autre dictionnaire imbriqué. La solution est récursive.
la source
Cette fonction fonctionne pour les valeurs non hachables. Je pense aussi qu'il est clair et facile à lire.
la source
Une implémentation récursive courte qui fonctionne pour les dictionnaires imbriqués:
Cela consommera les dicts a et b. Si quelqu'un connaît un bon moyen d'éviter cela sans recourir à des solutions partiellement itératives comme dans d'autres réponses, veuillez me le dire. J'aurais besoin d'un moyen de diviser un dict en tête et queue en fonction d'une clé.
Ce code est plus utile comme exercice de programmation, et est probablement beaucoup plus lent que les autres solutions ici qui mélangent récursivité et itération. La solution de Casse-Noisette est plutôt bonne pour les dictionnaires imbriqués.
la source
a
(et toute première valeur suivante)popitem
trouve. Il devrait également examiner d'autres éléments du même niveau. J'ai des paires de dictionnaires imbriqués où il renvoie la mauvaise réponse. (difficile de présenter un exemple à l'épreuve du temps ici, car il repose sur l'ordre depopitem
)Utilisez cet objet wrapper qui fournit une comparaison partielle et des différences intéressantes:
la source