2009-08-23 13 views
14

Estoy tratando de encontrar las teclas correspondientes en dos diccionarios diferentes. Cada uno tiene aproximadamente 600k entradas.Encontrar claves que coincidan en dos diccionarios grandes y hacerlo rápido

decir, por ejemplo:

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

Quiero imprimir el valor de Actinobacter (8.924.342) ya que coincide con un valor myRDP.

funciona El siguiente código, pero es muy lento:

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

He intentado lo siguiente pero siempre se traduce en una KeyError:

for key in myRDP: 
     print myNames[key] 

¿Existe tal vez una función implementada en C para hacer esto? He buscado en Google pero nada parece funcionar.

Gracias.

+0

Wow una Muchas de las respuestas aquí son bastante locas. Espero que escojas el camino de John. – Triptych

Respuesta

25

Use los juegos, ya que tienen incorporado un intersection método que debe ser rápida:

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

Por supuesto, tiene el tiempo de crear los conjuntos en primer lugar. Me pregunto si '[x para x en myRDP si x en myNames]' es más rápido o más lento que crear los dos conjuntos y tomar la intersección? –

+0

Sin el conjunto de datos de @ Audism, no podemos estar seguros, pero mi dinero estaría en que los sets sean más rápidos, a pesar de que tomará un tiempo crearlos. – RichieHindle

+0

Este también tomó aproximadamente 1 segundo. Realmente no noté ninguna diferencia de crear los conjuntos. –

36

usted puede hacer esto:

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

Su primer intento fue lento debido a que estaban comparando cada clave en myRDP con cada clave en myNames. En la jerga algorítmico, si myRDP tiene n elementos y myNames tiene m elementos, a continuación, que el algoritmo tomaría O (n × m) operaciones. ¡Para 600k elementos cada uno, esto es 360,000,000,000 de comparaciones!

Pero probar si un elemento en particular es la clave de un diccionario es rápido; de hecho, esta es una de las características definitorias de los diccionarios. En términos algorítmicos, la prueba key in dict es O (1) o constante. Por lo tanto, mi algoritmo tomará O (n) vez, que es una 600,000th de las veces.

+0

Por cierto, si ese material "O (n × m)" lo está confundiendo, esta pregunta podría ayudar: http://stackoverflow.com/questions/107165/big-o-for-eight-year-olds –

+0

I No estoy seguro de lo que hizo tu código. Creo que estaba imprimiendo cada clave de myRDP y myNames, pero felicitaciones por la explicación –

+2

Inspeccione cuidadosamente la segunda línea; no es 'for key in myNames', es' if key in myNames'. –

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

dict.get devuelve el valor por defecto que le dan (en este caso, None) si no existe la clave.

+0

Este tomó aproximadamente 1 segundo :) –

2

utilizar el método de get lugar:

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

Copia ambos diccionarios en el diccionario uno/matriz. Esto tiene sentido ya que tiene valores relacionados 1: 1. Entonces solo necesita una búsqueda, sin bucle de comparación, y puede acceder al valor relacionado directamente.

Ejemplo resultante Diccionario/Matriz:

[Name][Value1][Value2] 

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

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

...

+0

No hay una relación 1: 1. Debería haber un poco más de valores en myNames. ¿Esto todavía funcionaría? –

+0

Sí, esto todavía funcionaría. Simplemente crea una instancia de una nueva matriz y copie estos valores horizontalmente en la coincidencia. Vea el ejemplo de arriba. – Alex

5

Puede comenzar por encontrar las claves comunes y luego iterar sobre ellas.Las operaciones de conjunto deberían ser rápidas porque están implementadas en C, al menos en las versiones modernas de Python.

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

Aquí está mi código para hacer intersecciones, uniones, las diferencias y otras operaciones de conjuntos en los diccionarios:

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

en Python 3 sólo se puede hacer

myNames.keys() & myRDP.keys()

Cuestiones relacionadas