Tengo alrededor de 10 millones de valores que necesito poner en algún tipo de tabla de consulta, por lo que me preguntaba cuál sería más eficiente una lista o dict .
Sé que puedes hacer algo así para ambos:
if something in dict_of_stuff:
pass
y
if something in list_of_stuff:
pass
Mi pensamiento es que el dict será más rápido y más eficiente.
Gracias por tu ayuda.
EDITAR 1 Un
poco más de información sobre lo que estoy tratando de hacer. Problema de Euler 92 . Estoy haciendo una tabla de búsqueda para ver si un valor calculado ya está listo.
EDIT 2
Eficiencia para buscar.
EDITAR 3
No hay valores asociados con el valor ... entonces, ¿ sería mejor un conjunto ?
Respuestas:
Velocidad
Las búsquedas en las listas son O (n), las búsquedas en los diccionarios se amortizan O (1), con respecto al número de elementos en la estructura de datos. Si no necesita asociar valores, use conjuntos.
Memoria
Tanto los diccionarios como los conjuntos usan hashing y usan mucha más memoria que solo para el almacenamiento de objetos. Según AM Kuchling en Beautiful Code , la implementación intenta mantener el hash 2/3 lleno, por lo que puede desperdiciar bastante memoria.
Si no agrega nuevas entradas sobre la marcha (lo que hace, según 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.
fuente
Un dict es una tabla hash, por lo que es muy rápido encontrar las claves. Entonces, entre dict y list, dict sería más rápido. Pero si no tiene un valor para asociar, es aún mejor usar un conjunto. Es una tabla hash, sin la parte de "tabla".
EDITAR: para su nueva pregunta, SÍ, un conjunto sería mejor. Simplemente cree 2 conjuntos, uno para las secuencias terminadas en 1 y otro para las secuencias terminadas en 89. He resuelto con éxito este problema usando conjuntos.
fuente
set()
es exactamente lo que quieres O (1) búsquedas, y más pequeño que un dict.fuente
Hice algunas evaluaciones comparativas y resultó que dict es más rápido que la lista y el conjunto para conjuntos de datos grandes, ejecutando python 2.7.3 en una CPU i7 en Linux:
python -mtimeit -s 'd=range(10**7)' '5*10**6 in d'
10 bucles, lo mejor de 3: 64,2 ms por bucle
python -mtimeit -s 'd=dict.fromkeys(range(10**7))' '5*10**6 in d'
10000000 bucles, lo mejor de 3: 0.0759 usec por bucle
python -mtimeit -s 'from sets import Set; d=Set(range(10**7))' '5*10**6 in d'
1000000 bucles, lo mejor de 3: 0.262 usec por bucle
Como puede ver, dict es considerablemente más rápido que la lista y aproximadamente 3 veces más rápido que el conjunto. Sin embargo, en algunas aplicaciones es posible que aún desee elegir el conjunto por su belleza. Y si los conjuntos de datos son realmente pequeños (<1000 elementos), las listas funcionan bastante bien.
fuente
-s
opción es configurar eltimeit
entorno, es decir, no cuenta en el tiempo total. La-s
opción 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. Establecer y dictar el rendimiento es el mismo. Sin embargo, Dict tarda un poco más en inicializarse que el conjunto (tiempo total 13.580s v. 11.803s)python -mtimeit -s "d=set(range(10**7))" "5*10**6 in d"
Obtuve un buen rendimiento con el uso de Python 3.6.0 (10000000 bucles, lo mejor de 3: 0.0608 usec por bucle), aproximadamente lo mismo que el punto de referencia dict, así que gracias por su comentario.Quieres un dict.
Para las listas (sin clasificar) en Python, la operación "in" requiere un tiempo O (n) --- no es bueno cuando tiene una gran cantidad de datos. Un dict, por otro lado, es una tabla hash, por lo que puede esperar el tiempo de búsqueda O (1).
Como otros han señalado, puede elegir un conjunto (un tipo especial de dict) en su lugar, si solo tiene claves en lugar de pares clave / valor.
Relacionado:
fuente
in
operador aplicado a una lista ordenada funciona mejor que cuando se aplica a una lista sin clasificar (para una búsqueda de un valor aleatorio)? (No creo que sea relevante si se implementan internamente como vectores o como nodos en una lista vinculada).si los datos son únicos, set () será el más eficiente, pero de dos dict (que también requiere unicidad, oops :)
fuente
Como un nuevo conjunto de pruebas para mostrar @ EriF89 todavía tiene razón después de todos estos años:
Aquí también comparamos a
tuple
, que se sabe que son más rápidos quelists
(y usan menos memoria) en algunos casos de uso. En el caso de la tabla de búsqueda, eltuple
carenado no mejoró.Tanto el
dict
yset
funcionó muy bien. Esto trae un punto interesante relacionado con la respuesta de @SilentGhost sobre la unicidad: si el OP tiene valores de 10M en un conjunto de datos, y se desconoce si hay duplicados en ellos, entonces valdría la pena mantener un conjunto / dict de sus elementos en paralelo con el conjunto de datos real y las pruebas de existencia en ese conjunto / dict. ¡Es posible que los 10M puntos de datos solo tengan 10 valores únicos, que es un espacio mucho más pequeño para buscar!El error de SilentGhost sobre los dictos es realmente esclarecedor porque uno podría usar un dict para correlacionar datos duplicados (en valores) en un conjunto no duplicado (claves) y, por lo tanto, mantener un objeto de datos para contener todos los datos, pero aún así ser rápido como una tabla de búsqueda. Por ejemplo, una clave dict podría ser el valor que se busca, y el valor podría ser una lista de índices en una lista imaginaria donde ocurrió ese valor.
Por ejemplo, si la lista de datos de origen a buscar fuera
l=[1,2,3,1,2,1,4]
, podría optimizarse tanto para la búsqueda como para la memoria reemplazándola con este dict:Con este dict, uno puede saber:
2 in d
devuelveTrue
)d[2]
devuelve la lista de índices, donde se encontró datos en la lista de datos original:[1, 4]
)fuente
En realidad, no necesita almacenar 10 millones de valores en la tabla, por lo que no es un gran problema de ninguna manera.
Sugerencia: piense en cuán grande puede ser su resultado después de la primera operación de suma de cuadrados. El mayor resultado posible será mucho menor que 10 millones ...
fuente