2012-06-22 9 views
12

Ho una lista che assomiglia a questo:Python - intersezione tra una lista e le chiavi di un dizionario

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

Ho un dizionario che assomiglia a questo:

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

ho bisogno di ottenere filtrare il dictioary dove sono presenti solo le chiavi in ​​l1. Il dict dovrebbe essere simile a questo:

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

In sostanza un incrocio di una lista e le chiavi di una dict mentre tornava la sottosezione del dict.

Come faccio a farlo in modo efficiente quando il tempo è un problema per un set di grandi dimensioni?

Grazie

risposta

23

È possibile utilizzare il seguente codice:

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

EDIT: Come commentatori suggeriscono è possibile sostituire la prima linea con, in Python 2.x:

keys = set(l1).intersection(d1) 

E in Python 3.x:

keys = d1.keys() & l1 
+0

Si noti che in 3.x, una vista dizionario è impostata come, quindi non è necessario avvolgerla in 'set()'. Infatti, in 3.x, l'intera riga superiore può essere 'keys = d1.keys() & l1'. –

+1

@Lattyware non è necessario convertirlo in un set in 2.x o – jamylak

+4

Non sono nemmeno necessari i tasti(), 'set (l1) .intersection (d1)' – georg

0

È possibile utilizzare un elenco di comprensione nel costruttore dict:

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

Se siete preoccupati per la rimozione di chiavi duplicate, fare l1 in un set prima:

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

Una chiave potrebbe non essere in 'd1'. Questo non funzionerà. –

+0

Si noti inoltre che è possibile eseguire espressioni generatore di dict come nella mia soluzione. Quindi '{k: v per k, v in arr}'. Questo ha anche il vantaggio di trattare con i duplicati. – JPvdMerwe

+0

@JPvdMerwe È una comprensione del ditt, non un'espressione del generatore di dict - le espressioni del generatore sono pigre, una comprensione del ditt non lo è. –

4

In 3.x, questo può essere semplice come:

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

Sotto 2.7, è possibile utilizzare dict.viewkeys() per ricreare questa funzionalità:

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

Sotto le vecchie versioni di 2.x, è un po 'più dettagliato:

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

Ho controllato i documenti. Sembra che 'viewkeys()' sia disponibile in 2.7, non solo 2.7.3. Appare nella mia copia di Python 2.7.1 – JPvdMerwe

+0

@JPvdMerwe Buono a sapersi, aggiornato. –

3

Non sei sicuro di ogni performance soluzione, ma lo farei:

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

Funzionerà anche quando un membro di l1 non è una chiave in d1, su cui molti altri falliranno. –

0

Definire efficiente. Comunque ecco cosa vorrei fare. Se fosse troppo lento probabilmente lo sposterei su 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

Se l'allocazione della memoria e la deallocazione stanno rendendo questo processo troppo lungo, itertools in soccorso.

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

Ciò non inutilmente allocare memoria per collezione nuova, e l1 potrebbe facilmente essere un iteratore invece di una lista.

Problemi correlati