2012-06-22 30 views
12

Tengo una lista que tiene este aspecto:Python - intersección entre una lista y claves de un diccionario

l1 = ['200:200', '90:728'] 

tengo un diccionario que tiene este aspecto:

d1 = {'200:200':{'foo':'bar'},'300:300':{'foo':'bar'}} 

Necesito llegar filtra el dictioary donde solo las claves están en l1. El dict debería tener este aspecto:

result = {'200:200':{'foo':'bar'}} 

En esencia, un cruce de una lista y las claves de un diccionario, mientras que devolver la subsección de la dict.

¿Cómo hago esto de manera eficiente cuando el tiempo es un problema para un conjunto grande?

Gracias

Respuesta

23

Usted puede utilizar el siguiente código:

keys = set(l1).intersection(set(d1.keys())) 
result = {k:d1[k] for k in keys} 

EDIT: Como comentaristas sugieren que puede sustituir a la primera línea con, en Python 2.x:

keys = set(l1).intersection(d1) 

Y en Python 3.x:

keys = d1.keys() & l1 
+0

Tenga en cuenta que en 3.x, una vista del diccionario se configura como, por lo que no necesita envolverlo en 'set()'. De hecho, en 3.x, toda la línea superior puede ser 'keys = d1.keys() & l1'. –

+1

@Lattyware no necesita convertirlo en un conjunto en 2.x – jamylak

+4

Ni siquiera necesita las teclas(), 'set (l1) .intersection (d1)' – georg

0

Se puede utilizar una lista de comprensión del constructor dict:

result = dict([(k,d1[k]) for k in l1 if k in d1]) 

Si usted está preocupado acerca de la eliminación de duplicados de las llaves, hacer L1 en un conjunto en primer lugar:

result = dict([(k,d1[k]) for k in set(l1) if k in d1]) 
+0

Una clave puede no estar en 'd1'. Esto no funcionará –

+0

También tenga en cuenta que puede hacer expresiones generadoras dict como en mi solución. Entonces '{k: v para k, v en arr}'. Esto incluso tiene el beneficio de lidiar con duplicados. – JPvdMerwe

+0

@JPvdMerwe Es una comprensión dict, no una expresión del generador de dict: las expresiones del generador son flojas, una comprensión dict no. –

4

En 3.x, esto puede ser tan simple como:

>>> {k: d1[k] for k in (d1.keys() & l1)} 
{'200:200': {'foo': 'bar'}} 

Bajo 2.7, puede utilizar dict.viewkeys() para recrear esta funcionalidad:

>>> {k: d1[k] for k in (d1.viewkeys() & l1)} 
{'200:200': {'foo': 'bar'}} 

En las versiones anteriores de 2.x, que es un poco más detallado:

>>> {k: d1[k] for k in (set(d1).intersection(l1))} 
{'200:200': {'foo': 'bar'}} 
+0

Revisé los documentos. Parece que 'viewkeys()' está disponible en 2.7, no solo en 2.7.3. Aparece en mi copia de Python 2.7.1 – JPvdMerwe

+0

@JPvdMerwe. Es bueno saberlo, actualizado. –

3

No está seguro acerca de cada rendimiento de la solución, pero me gustaría hacer:

{k: v for k, v in d1.items() if k in l1} 
+2

Esto funcionará incluso cuando un miembro de l1 no es una clave en d1, y muchos otros fallarán. –

0

Definir eficiente. De todos modos, esto es lo que haría. Si fuera demasiado lento, probablemente lo movería a Cython.

s1 = set(l1) 
s2 = set(d1.keys()) 
s3 = s1 & s2 
# now you can access d1 using only keys in s3, or construct a new dict if you like 
d2 = dict([(k,d1[k]) for k in s3]) 
0

Si la asignación de memoria y la desasignación hacen que este proceso sea demasiado largo, itertools al rescate.

import itertools 
result = {dict_key:d1[dict_key] for dict_key in itertools.ifilter(lambda list_item: list_item in d1, l1) } 

Esto no asigna innecesariamente la memoria para una colección totalmente nueva, y L1 podría ser fácilmente un iterador en lugar de una lista.

Cuestiones relacionadas