Estoy tratando de escribir un método de filtro personalizado que toma un número arbitrario de kwargs y devuelve una lista que contiene los elementos de una lista similar a una base de datos que contiene esos kwargs .
Por ejemplo, suponga que d1 = {'a':'2', 'b':'3'}
y d2
= lo mismo. d1 == d2
resulta en Verdadero. Pero supongamos d2
= lo mismo más un montón de otras cosas. Mi método necesita poder decir si d1 en d2 , pero Python no puede hacer eso con diccionarios.
Contexto:
Tengo una clase de palabras, y cada objeto tiene propiedades como word
, definition
, part_of_speech
, y así sucesivamente. Quiero poder llamar a un método de filtro en la lista principal de estas palabras, como Word.objects.filter(word='jump', part_of_speech='verb-intransitive')
. No puedo entender cómo administrar estas claves y valores al mismo tiempo. Pero esto podría tener una mayor funcionalidad fuera de este contexto para otras personas.
fuente
d1.viewitems() <= d2.viewitems()
. Las ejecuciones de Timeit mostraron una mejora de rendimiento 3 veces superior. Si no se puede mezclar, incluso usarlo eniteritems()
lugar deitems()
conduce a una mejora de aproximadamente 1.2x. Esto se hizo usando Python 2.7.items()
devolverá vistas ligeras en lugar de copias. No es necesaria ninguna optimización adicional.En Python 3, puede usar
dict.items()
para obtener una vista similar a un conjunto de los elementos de dict. Luego puede usar el<=
operador para probar si una vista es un "subconjunto" de la otra:En Python 2.7, use
dict.viewitems()
para hacer lo mismo:En Python 2.6 y versiones anteriores, necesitará una solución diferente, como usar
all()
:fuente
d1.items() <= d2.items()
d1.items() <= d2.items()
realidad están comparando 2 listas de tuplas, sin un orden particular, por lo que el resultado final probablemente no será confiable. Por esta razón, cambio a la respuesta de @blubberdiblub.d1.items() <= d2.items()
es un comportamiento indefinido. No está documentado en los documentos oficiales y, lo que es más importante, no está probado: github.com/python/cpython/blob/… Así que esto depende de la implementación.collections.abc.Set
están disponibles"Nota para las personas que necesitan esto para las pruebas unitarias: también hay un
assertDictContainsSubset()
método en laTestCase
clase de Python .http://docs.python.org/2/library/unittest.html?highlight=assertdictcontainssubset#unittest.TestCase.assertDictContainsSubset
Sin embargo, está obsoleto en 3.2, no estoy seguro de por qué, tal vez haya un reemplazo para él.
fuente
para claves y valores, verifique el uso:
set(d1.items()).issubset(set(d2.items()))
si necesita verificar solo las claves:
set(d1).issubset(set(d2))
fuente
d1={'a':1,'b':2}; d2={'a':2,'b':1}
-> el segundo fragmento volveráTrue
...{'a', 'b'}
es de hecho un subconjunto de{'a', 'b'}
;)Para completar, también puede hacer esto:
Sin embargo, no hago ningún reclamo con respecto a la velocidad (o falta de ella) o legibilidad (o falta de ella).
fuente
small.viewitems() <= big.viewitems()
fueron prometedoras, pero con una advertencia: si su programa también se puede usar en Python 2.6 (o incluso en una versión inferior), end1.items() <= d2.items()
realidad se están comparando 2 listas de tuplas, sin un orden en particular, por lo que el resultado final probablemente será no fiable. Por esa razón, cambio a la respuesta de @blubberdiblub. Voto a favor.dict
como clase base? ¿Qué pasa si no lo ha hecho y todavía se comporta como undict
? ¿Qué pasa sismall
ybig
contienen valores de diferente tipo en una clave coincidente que todavía se comporta como dict?False
cuando los valores de los dictados pasados son diferentes para las claves coincidentes). O en otras palabras: la solución para los dictados anidados no es necesariamente un reemplazo directo según el caso de uso.contexto:
fuente
Mi función para el mismo propósito, haciendo esto de forma recursiva:
En su ejemplo,
dictMatch(d1, d2)
debería devolver True incluso si d2 tiene otras cosas, además de que también se aplica a niveles inferiores:Notas: Podría haber una solución aún mejor que evite la
if type(pvalue) is dict
cláusula y se aplique a una gama aún más amplia de casos (como listas de hashes, etc.). Además, la recursividad no está limitada aquí, así que úsala bajo tu propio riesgo. ;)fuente
Aquí hay una solución que también se repite correctamente en listas y conjuntos contenidos en el diccionario. También puede usar esto para listas que contengan dictados, etc.
fuente
Este problema aparentemente sencillo me cuesta un par de horas de investigación para encontrar una solución 100% confiable, así que documenté lo que encontré en esta respuesta.
Hablando con "Pythonic-ally",
small_dict <= big_dict
sería la forma más intuitiva, pero es una lástima que no funcione .{'a': 1} < {'a': 1, 'b': 2}
aparentemente funciona en Python 2, pero no es confiable porque la documentación oficial lo menciona explícitamente. Vaya a la búsqueda "Los resultados distintos de la igualdad se resuelven de forma coherente, pero no se definen de otra manera". en esta sección . Sin mencionar que comparar 2 dictados en Python 3 da como resultado una excepción TypeError.La segunda cosa más intuitiva es solo
small.viewitems() <= big.viewitems()
para Python 2.7 ysmall.items() <= big.items()
para Python 3. Pero hay una advertencia: es potencialmente defectuoso . Si su programa podría potencialmente usarse en Python <= 2.6, end1.items() <= d2.items()
realidad está comparando 2 listas de tuplas, sin un orden particular, por lo que el resultado final no será confiable y se convertirá en un error desagradable en su programa. No estoy interesado en escribir otra implementación para Python <= 2.6, pero todavía no me siento cómodo con que mi código tenga un error conocido (incluso si está en una plataforma no compatible). De modo que abandono este enfoque.Me establezco con la respuesta de @blubberdiblub (el crédito es para él):
def is_subdict(small, big): return dict(big, **small) == big
Vale la pena señalar que esta respuesta se basa en el
==
comportamiento entre dictados, que está claramente definido en el documento oficial, por lo que debería funcionar en todas las versiones de Python . Ir a buscar:fuente
Aquí hay una solución recursiva general para el problema dado:
NOTA: El código original fallaría en ciertos casos, los créditos por la reparación van a @ olivier-melançon
fuente
if not set(value) <= set(superset[key])
Si no les importa usar
pydash
existeis_match
allí, lo que hace exactamente eso:fuente
Sé que esta pregunta es antigua, pero aquí está mi solución para verificar si un diccionario anidado es parte de otro diccionario anidado. La solución es recursiva.
fuente
Esta función funciona para valores no hash. También creo que es claro y fácil de leer.
fuente
Una implementación recursiva corta que funciona para diccionarios anidados:
Esto consumirá los dictados ayb. Si alguien conoce una buena manera de evitar eso sin recurrir a soluciones parcialmente iterativas como en otras respuestas, dímelo. Necesitaría una forma de dividir un dictado en cabeza y cola según una clave.
Este código es más útil como ejercicio de programación, y probablemente sea mucho más lento que otras soluciones aquí que mezclan recursividad e iteración. La solución de @ Nutcracker es bastante buena para los diccionarios anidados.
fuente
a
(y cualquier primer valor posterior)popitem
encuentra. También debe examinar otros elementos del mismo nivel. Tengo pares de dictados anidados en los que devuelve la respuesta incorrecta. (es difícil presentar un ejemplo a prueba de futuro aquí, ya que se basa en el orden depopitem
)Utilice este objeto contenedor que proporciona una comparación parcial y diferencias agradables:
fuente