2009-08-23 11 views
14

Sto cercando di trovare le chiavi corrispondenti in due dizionari diversi. Ognuno ha circa 600k voci.Trovare chiavi corrispondenti in due grandi dizionari e farlo velocemente

diciamo per esempio:

myRDP = { 'Actinobacter': 'GATCGA...TCA', 'subtilus sp.': 'ATCGATT...ACT' } 
    myNames = { 'Actinobacter': '8924342' } 

voglio stampare il rapporto qualità-Actinobacter (8.924.342), in quanto corrisponde a un valore in myRDP.

Il seguente codice funziona, ma è molto lento:

for key in myRDP: 
     for jey in myNames: 
      if key == jey: 
       print key, myNames[key] 

Ho provato quanto segue ma si traduce sempre in un KeyError:

for key in myRDP: 
     print myNames[key] 

c'è forse una funzione implementata in C per fare questo? Ho cercato su Google ma niente sembra funzionare.

Grazie.

+0

Wow un molte delle risposte qui sono piuttosto stravaganti. Spero che tu scelga la via di John. – Triptych

risposta

25

Usa insiemi, perché hanno un built-in intersection metodo che dovrebbe essere breve:

myRDP = { 'Actinobacter': 'GATCGA...TCA', 'subtilus sp.': 'ATCGATT...ACT' } 
myNames = { 'Actinobacter': '8924342' } 

rdpSet = set(myRDP) 
namesSet = set(myNames) 

for name in rdpSet.intersection(namesSet): 
    print name, myNames[name] 

# Prints: Actinobacter 8924342 
+0

Ovviamente, hai il colpo di tempo di creare i set in primo luogo. Mi chiedo se '[x per x in myRDP se x in myNames]' sia più veloce o più lento di creare i due set e prendere l'intersezione? –

+0

Senza il set di dati di @ Audism non possiamo esserne sicuri, ma il mio denaro sarebbe sul set più veloce, anche se ci vorrà del tempo per crearlo. – RichieHindle

+0

Anche questo ha richiesto circa 1 secondo. Non ho notato alcuna differenza dalla creazione dei set. –

36

Si potrebbe fare questo:

for key in myRDP: 
    if key in myNames: 
     print key, myNames[key] 

Il primo tentativo è stato lento a causa di comparare ogni chiave nella myRDP con ogni chiave myNames. Nel gergo algoritmico, se myRDP ha n elementi e myNames ha m elementi, allora tale algoritmo prenderebbe O (n × m) operazioni. Per 600k elementi ciascuno, questo è 360.000.000.000 confronti!

Ma testare se un particolare elemento è una chiave di un dizionario è veloce - in effetti, questa è una delle caratteristiche che definiscono i dizionari. In termini algoritmici, il test key in dict è O (1) o tempo costante. Quindi il mio algoritmo prenderà tempo O (n), che è una 600.000 delle volte.

+0

A proposito, se questa roba "O (n × m)" ti confonde, questa domanda potrebbe aiutarti: http://stackoverflow.com/questions/107165/big-o-for-eight-year-olds –

+0

I non sono sicuro di cosa ha fatto il tuo codice. Penso che stia stampando ogni chiave da myRDP e myNames, ma complimenti per la spiegazione –

+2

Ispeziona attentamente la seconda riga; non è 'per la chiave in myNames', è' if key in myNames'. –

8
for key in myRDP: 
    name = myNames.get(key, None) 
    if name: 
     print key, name 

dict.get restituisce il valore di default si dà (in questo caso, None) se la chiave non esiste.

+0

Questo ha impiegato circa 1 secondo :) –

2

utilizzare il metodo get invece:

for key in myRDP: 
    value = myNames.get(key) 
    if value != None: 
     print key, "=", value 
0

copiare entrambi i dizionari in uno dizionario/array. Questo ha senso in quanto hai valori relativi a 1: 1. Quindi è necessaria solo una ricerca, nessun ciclo di confronto e può accedere direttamente al valore correlato.

Esempio risultante Dictionary/Array:

[Name][Value1][Value2] 

[Actinobacter][GATCGA...TCA][8924342] 

[XYZbacter][BCABCA...ABC][43594344] 

...

+0

Non c'è una relazione 1: 1. Ci dovrebbero essere leggermente più valori in myNames. Funzionerebbe ancora? –

+0

Sì, funzionerebbe ancora. Basta istanziare un nuovo array e copiare questi valori orizzontalmente insieme sulla partita. Vedi l'esempio sopra. – Alex

5

Si potrebbe iniziare trovando le chiavi comuni e quindi eseguendo un'iterazione su di esse.Le operazioni di set dovrebbero essere veloci perché sono implementate in C, almeno nelle versioni moderne di Python.

common_keys = set(myRDP).intersection(myNames) 
for key in common_keys: 
    print key, myNames[key] 
0

Ecco il mio codice per fare le intersezioni, i sindacati, le differenze, e le altre operazioni di set on dizionari:

class DictDiffer(object): 
    """ 
    Calculate the difference between two dictionaries as: 
    (1) items added 
    (2) items removed 
    (3) keys same in both but changed values 
    (4) keys same in both and unchanged values 
    """ 
    def __init__(self, current_dict, past_dict): 
     self.current_dict, self.past_dict = current_dict, past_dict 
     self.set_current, self.set_past = set(current_dict.keys()), set(past_dict.keys()) 
     self.intersect = self.set_current.intersection(self.set_past) 
    def added(self): 
     return self.set_current - self.intersect 
    def removed(self): 
     return self.set_past - self.intersect 
    def changed(self): 
     return set(o for o in self.intersect if self.past_dict[o] != self.current_dict[o]) 
    def unchanged(self): 
     return set(o for o in self.intersect if self.past_dict[o] == self.current_dict[o]) 

if __name__ == '__main__': 
    import unittest 
    class TestDictDifferNoChanged(unittest.TestCase): 
     def setUp(self): 
      self.past = dict((k, 2*k) for k in range(5)) 
      self.current = dict((k, 2*k) for k in range(3,8)) 
      self.d = DictDiffer(self.current, self.past) 
     def testAdded(self): 
      self.assertEqual(self.d.added(), set((5,6,7))) 
     def testRemoved(self):  
      self.assertEqual(self.d.removed(), set((0,1,2))) 
     def testChanged(self): 
      self.assertEqual(self.d.changed(), set()) 
     def testUnchanged(self): 
      self.assertEqual(self.d.unchanged(), set((3,4))) 
    class TestDictDifferNoCUnchanged(unittest.TestCase): 
     def setUp(self): 
      self.past = dict((k, 2*k) for k in range(5)) 
      self.current = dict((k, 2*k+1) for k in range(3,8)) 
      self.d = DictDiffer(self.current, self.past) 
     def testAdded(self): 
      self.assertEqual(self.d.added(), set((5,6,7))) 
     def testRemoved(self):  
      self.assertEqual(self.d.removed(), set((0,1,2))) 
     def testChanged(self): 
      self.assertEqual(self.d.changed(), set((3,4))) 
     def testUnchanged(self): 
      self.assertEqual(self.d.unchanged(), set()) 
    unittest.main() 
4

in Python 3 si può solo fare

myNames.keys() & myRDP.keys()

Problemi correlati