J'ai environ 10 millions de valeurs que je dois mettre dans un type de table de recherche, alors je me demandais quelle serait la plus efficace une liste ou un dict ?
Je sais que vous pouvez faire quelque chose comme ça pour les deux:
if something in dict_of_stuff:
pass
et
if something in list_of_stuff:
pass
Je pense que le dict sera plus rapide et plus efficace.
Merci de votre aide.
EDIT 1 Un
peu plus d'informations sur ce que j'essaie de faire. Problème d'Euler 92 . Je crée une table de consultation pour voir si une valeur calculée a été entièrement calculée.
EDIT 2
Efficacité pour la recherche.
EDIT 3
Il n'y a pas de valeurs associées à la valeur ... alors un ensemble serait-il meilleur?
Réponses:
La vitesse
Les recherches dans les listes sont O (n), les recherches dans les dictionnaires sont amorties O (1), par rapport au nombre d'éléments dans la structure de données. Si vous n'avez pas besoin d'associer des valeurs, utilisez des ensembles.
Mémoire
Les dictionnaires et les ensembles utilisent le hachage et ils utilisent beaucoup plus de mémoire que pour le stockage d'objets uniquement. Selon AM Kuchling dans Beautiful Code , l'implémentation essaie de garder le hachage 2/3 complet, vous risquez donc de perdre un peu de mémoire.
Si vous n'ajoutez pas de nouvelles entrées à la volée (ce que vous faites, en fonction de votre question mise à jour), il peut être utile de trier la liste et d'utiliser la recherche binaire. C'est O (log n), et est susceptible d'être plus lent pour les chaînes, impossible pour les objets qui n'ont pas un ordre naturel.
la source
Un dict est une table de hachage, il est donc très rapide de trouver les clés. Ainsi, entre dict et list, dict serait plus rapide. Mais si vous n'avez pas de valeur à associer, il est encore mieux d'utiliser un ensemble. C'est une table de hachage, sans la partie "table".
EDIT: pour votre nouvelle question, OUI, un ensemble serait mieux. Créez simplement 2 ensembles, un pour les séquences terminées en 1 et l'autre pour les séquences terminées en 89. J'ai résolu avec succès ce problème en utilisant des ensembles.
la source
set()
est exactement ce que vous voulez. O (1) recherches, et plus petit qu'un dict.la source
J'ai fait quelques analyses comparatives et il s'avère que dict est plus rapide que la liste et défini pour les grands ensembles de données, exécutant python 2.7.3 sur un processeur i7 sous Linux:
python -mtimeit -s 'd=range(10**7)' '5*10**6 in d'
10 boucles, le meilleur de 3: 64,2 ms par boucle
python -mtimeit -s 'd=dict.fromkeys(range(10**7))' '5*10**6 in d'
10000000 boucles, meilleur de 3: 0,0759 usec par boucle
python -mtimeit -s 'from sets import Set; d=Set(range(10**7))' '5*10**6 in d'
1000000 boucles, meilleur de 3: 0,262 usec par boucle
Comme vous pouvez le voir, dict est considérablement plus rapide que list et environ 3 fois plus rapide que set. Dans certaines applications, vous voudrez peut-être toujours choisir un ensemble pour sa beauté. Et si les ensembles de données sont vraiment petits (<1000 éléments), les listes fonctionnent plutôt bien.
la source
-s
option est de paramétrer l'timeit
environnement, c'est à dire qu'il ne compte pas dans le temps total. L'-s
option n'est exécutée qu'une seule fois. Sur Python 3.3, j'obtiens ces résultats: gen (plage) -> 0,229 usec, liste -> 157 msec, dict -> 0,0806 usec, set -> 0,0807 usec. Les performances de set et de dict sont les mêmes. Dict prend cependant un peu plus de temps à s'initialiser que défini (temps total 13,580s contre 11,803s)python -mtimeit -s "d=set(range(10**7))" "5*10**6 in d"
J'obtiens de bonnes performances avec l' utilisation de Python 3.6.0 (10000000 boucles, le meilleur de 3: 0,0608 usec par boucle), à peu près les mêmes que le benchmark dict alors merci pour votre commentaire.Vous voulez un dict.
Pour les listes (non triées) en Python, l'opération "in" nécessite un temps O (n) --- pas bon lorsque vous avez une grande quantité de données. Un dict, en revanche, est une table de hachage, vous pouvez donc vous attendre à un temps de recherche O (1).
Comme d'autres l'ont noté, vous pouvez choisir un ensemble (un type spécial de dict) à la place, si vous n'avez que des clés plutôt que des paires clé / valeur.
En relation:
la source
in
opérateur appliqué à une liste triée fonctionne mieux que lorsqu'il est appliqué à une liste non triée (pour une recherche d'une valeur aléatoire)? (Je ne pense pas qu'ils soient implémentés en interne en tant que vecteurs ou en tant que nœuds dans une liste chaînée est pertinent.)si les données sont uniques, set () sera le plus efficace, mais de deux - dict (qui nécessite également unicité, oups :)
la source
En tant que nouvel ensemble de tests à montrer, @ EriF89 a toujours raison après toutes ces années:
Ici, nous comparons également a
tuple
, qui sont connus pour être plus rapides quelists
(et utiliser moins de mémoire) dans certains cas d'utilisation. Dans le cas d'une table de consultation, letuple
carénage n'est pas meilleur.Le
dict
etset
ont très bien performé. Cela soulève un point intéressant lié à la réponse @SilentGhost sur l'unicité: si l'OP a 10M de valeurs dans un ensemble de données, et qu'on ne sait pas s'il y a des doublons, alors il vaudrait la peine de garder un ensemble / dict de ses éléments en parallèle avec l'ensemble de données réel, et tester l'existence dans cet ensemble / dict. Il est possible que les 10 millions de points de données n'aient que 10 valeurs uniques, ce qui est un espace beaucoup plus petit pour la recherche!L'erreur de SilentGhost à propos des dictionnaires est en fait éclairante car on pourrait utiliser un dict pour corréler des données dupliquées (en valeurs) dans un ensemble non dupliqué (clés), et ainsi conserver un objet de données pour contenir toutes les données, tout en restant rapide comme table de recherche. Par exemple, une clé dict pourrait être la valeur recherchée, et la valeur pourrait être une liste d'indices dans une liste imaginaire où cette valeur s'est produite.
Par exemple, si la liste de données source à rechercher était
l=[1,2,3,1,2,1,4]
, elle pourrait être optimisée pour la recherche et la mémoire en la remplaçant par ce dict:Avec ce dict, on peut savoir:
2 in d
RenvoieTrue
)d[2]
retourne la liste des indices où les données ont été énumérées dans la liste de données d' origine:[1, 4]
)la source
Vous n'avez pas vraiment besoin de stocker 10 millions de valeurs dans la table, ce n'est donc pas un gros problème de toute façon.
Astuce: pensez à la taille de votre résultat après la première opération de somme des carrés. Le plus grand résultat possible sera bien inférieur à 10 millions ...
la source