2009-02-04 12 views
112

Tengo cerca de 10 millones de valores que tengo que poner en algún tipo de tabla de búsqueda, así que me preguntaba lo que sería más eficiente una lista o dict?Python: Lista vs Dict para la tabla de búsqueda de

Sé que usted puede hacer algo como esto para ambos:

if something in dict_of_stuff: 
    pass 

y

if something in list_of_stuff: 
    pass 

Mi pensamiento es el dict será más rápido y más eficiente.

Gracias por su ayuda.

EDIT 1
poco más de información sobre lo que estoy tratando de hacer. Euler Problem 92. Estoy haciendo una tabla de consulta para ver si un valor calculado ya ha sido calculado.

EDIT 2
Eficiencia para buscar.

EDITAR 3
No existen valores assosiated con el valor ... así que sería un conjunto ser mejor?

+1

Eficiencia en términos de qué? ¿Insertar? ¿Buscar? Consumo de memoria? ¿Está comprobando la existencia pura de valor o hay algún metadato asociado a él? – truppo

+0

Como nota al margen, no necesita una lista de 10 millones o dict para ese problema específico, pero uno mucho más pequeño. – sfotiadis

+0

¿Qué sucede si la tabla es una tupla en lugar de una lista? ¿Están los elementos de la tupla hash, o es solo una lista inmutable? – RufusVS

Respuesta

154

velocidad

búsquedas en las listas son O (n), las búsquedas en los diccionarios se amortizan O (1), en relación con el número de elementos en la estructura de datos. Si no necesita asociar valores, use conjuntos.

memoria

Ambos diccionarios y conjuntos utilizan hash y utilizan mucha más memoria que sólo para el almacenamiento de objetos. De acuerdo con A.M. Kuchling en Beautiful Code, la implementación intenta mantener el hash 2/3 lleno, por lo que puede perder bastante memoria.

Si no agrega nuevas entradas sobre la marcha (lo que hace, en función de su pregunta actualizada), podría valer la pena ordenar la lista y usar la búsqueda binaria. Esto es O (log n), y es probable que sea más lento para las cadenas, imposible para los objetos que no tienen un orden natural.

+0

la ordenación de lista es O (n log n) – SilentGhost

+6

Sí, pero se trata de una operación única si el contenido nunca cambia . La búsqueda binaria es O (log n). –

+0

OTOH, 10 millones de enteros tomarán, ¿qué, 40 millones de bytes? Si el hash está 2/3 lleno, eso va a 60 millones, y habrá gastos generales (¿alguien sabe cuánto?), Pero todo debería caber en unos pocos cientos de megas de memoria. Pudo haber sido un problema hace diez años, pero no es realmente ahora. –

6

si los datos son conjunto único() será el más eficiente, sino de dos - dict (que también requiere singularidad, oops :)

+1

no realmente ... los datos deben ser únicos para el dict también. – nosklo

+0

me di cuenta cuando vi mi respuesta publicada%) – SilentGhost

+1

@SilentGhost si la respuesta es incorrecta, ¿por qué no eliminarla? demasiado mal para las votaciones ascendentes, pero eso sucede (bueno, _ sucedió_) –

32

un diccionario es una tabla hash, por lo que es muy rápido para encontrar la llaves. Entonces entre dict y list, dict sería más rápido. Pero si no tiene un valor para asociar, es incluso mejor usar un conjunto. Es una tabla hash, sin la parte "tabla".


EDITAR: para su nueva pregunta, SÍ, un conjunto sería mejor. Solo crea 2 juegos, uno para las secuencias que terminaron en 1 y otro para las secuencias que terminaron en 89. He resuelto este problema exitosamente usando sets.

5

Quieres un dict.

Para las listas (sin clasificar) en Python, la operación "in" requiere O (n) tiempo --- no es bueno cuando tiene una gran cantidad de datos. Un dict, por otro lado, es una tabla hash, por lo que puede esperar O (1) tiempo de búsqueda.

Como han notado otros, puede elegir un conjunto (un tipo especial de dict) en su lugar, si solo tiene claves en lugar de pares clave/valor.

relacionadas:

  • Python wiki: información sobre la complejidad del tiempo de las operaciones de contenedores de Python.
  • SO: Operación contenedor de tiempo y memoria complejidades Python
+1

Incluso para las listas ordenadas, "in" es O (n). –

+1

Para una lista vinculada, sí --- pero las "listas" en Python son lo que la mayoría de las personas llamarían vectores, que proporcionan acceso indexado en O (1) y una operación de búsqueda en O (log n), cuando se ordenan. – zweiterlinde

+0

¿Está diciendo que el operador 'in' aplicado a una lista ordenada funciona mejor que cuando se aplica a una lista no ordenada (para una búsqueda de un valor aleatorio)?(No creo que si se implementan internamente como vectores o como nodos en una lista enlazada es relevante). – martineau

0

En realidad, no es necesario almacenar 10 millones de valores en la tabla, por lo que no es gran cosa.

Sugerencia: piense en qué tan grande puede ser su resultado después de la primera suma de cuadrados de operación. El mayor resultado posible será mucho menor que 10 millones ...

24

set() es exactamente lo que desea. O (1) búsquedas, y más pequeño que un dict.

21

hice un poco de evaluación comparativa y resulta que dict es más rápido que ambos lista y establecer para grandes conjuntos de datos, ejecutar Python 2.7.3 en una CPU i7 en Linux:

  • python -mtimeit -s 'd=range(10**7)' '5*10**6 in d'

    10 bucles, mejor de 3: 64,2 mseg por bucle

  • python -mtimeit -s 'd=dict.fromkeys(range(10**7))' '5*10**6 in d'

    10000000 bucles, mejor de 3: 0.075 9 USEC por lazo

  • python -mtimeit -s 'from sets import Set; d=Set(range(10**7))' '5*10**6 in d'

    1000000 bucles, mejor de 3: 0,262 USEC por lazo

Como se puede ver, dict es considerablemente más rápido que lista y aproximadamente 3 veces más rápido que el conjunto . Sin embargo, en algunas aplicaciones es posible que desee elegir establecer por su belleza. Y si los conjuntos de datos son realmente pequeños (< 1000 elementos), las listas funcionan bastante bien.

+0

¿No debería ser exactamente lo opuesto? Lista: 10 * 64.2 * 1000 = 642000 usec, dict: 10000000 * 0.0759 = 759000 usec y set: 1000000 * 0.262 = 262000 usec ... por lo que los sets son los más rápidos, seguidos por la lista y con dict como last en su ejemplo. ¿O me estoy perdiendo algo? – andzep

+0

... pero la pregunta para mí aquí es: ¿qué mide realmente este tiempo? No es el tiempo de acceso para una lista dada, dict o set, sino mucho más, el tiempo y los bucles para crear la lista, dict, set y finalmente para encontrar y acceder a un valor. Entonces, ¿tiene esto que ver con la pregunta en absoluto? ... Aunque es interesante ... – andzep

+5

@andzep, está equivocado, la opción '-s' es configurar el entorno' timeit', es decir, no cuenta en el tiempo total. La opción '-s' se ejecuta solo una vez. En Python 3.3, obtengo estos resultados: gen (rango) -> 0.229 usec, lista -> 157 mseg, dict -> 0.0806 usec, set -> 0.0807 usec. El rendimiento de set y dict es el mismo. Dict, sin embargo, tarda un poco más en inicializarse que el establecido (tiempo total 13.580s v. 11.803s) – sleblanc

Cuestiones relacionadas