Vous avez demandé lequel était le plus efficace. En supposant que vous parlez de la vitesse d'exécution: Si vos données sont petites, cela n'a pas d'importance. S'il est grand et typique, le cas "déjà existant" se produira beaucoup plus souvent que le cas "non existant". Cette observation explique certains des résultats. Vous trouverez ci-dessous un code pouvant être utilisé avec le module timeit
pour explorer la vitesse sans surcharge de lecture de fichier. J'ai pris la liberté d'ajouter une 5ème méthode, qui n'est pas non-compétitive et fonctionnera sur n'importe quel Python à partir d'au moins 1.5.2 [testé].
from collections import defaultdict, Counter
def tally0(iterable):
# DOESN'T WORK -- common base case for timing
d = {}
for item in iterable:
d[item] = 1
return d
def tally1(iterable):
d = {}
for item in iterable:
if item in d:
d[item] += 1
else:
d[item] = 1
return d
def tally2(iterable):
d = {}
for item in iterable:
try:
d[item] += 1
except KeyError:
d[item] = 1
return d
def tally3(iterable):
d = defaultdict(int)
for item in iterable:
d[item] += 1
def tally4(iterable):
d = Counter()
for item in iterable:
d[item] += 1
def tally5(iterable):
d = {}
dg = d.get
for item in iterable:
d[item] = dg(item, 0) + 1
return d
course typique (dans la fenêtre Windows XP "Invite de commandes"):
prompt>\python27\python -mtimeit -s"t=1000*'now is the winter of our discontent made glorious summer by this son of york';import tally_bench as tb" "tb.tally1(t)"
10 loops, best of 3: 29.5 msec per loop
Voici les résultats (msec par boucle):
0 base case 13.6
1 if k in d 29.5
2 try/except 26.1
3 defaultdict 23.4
4 Counter 79.4
5 d.get(k, 0) 29.2
Un autre essai de synchronisation:
prompt>\python27\python -mtimeit -s"from collections import defaultdict;d=defaultdict(int)" "d[1]+=1"
1000000 loops, best of 3: 0.309 usec per loop
prompt>\python27\python -mtimeit -s"from collections import Counter;d=Counter()" "d[1]+=1"
1000000 loops, best of 3: 1.02 usec per loop
La vitesse de Counter
est probablement due à son implémentation partielle en code Python alors que defaultdict
est entièrement en C (en 2.7, au moins).
Notez que Counter()
est pas seulement « sucre syntaxique » pour defaultdict(int)
- il met en œuvre une bag
complète alias multiset
objet - voir la documentation pour plus de détails; ils peuvent vous éviter de réinventer la roue si vous avez besoin d'un post-traitement de fantaisie. Si tout ce que vous voulez faire est de compter les choses, utilisez defaultdict
.
Mise à jour en réponse à une question de @Steven Rumbalski: « » » Je suis curieux, ce qui se passe si vous déplacez le itérables dans le constructeur du compteur: d = Compteur (itérables) (je python 2.6 et ne peut pas le tester) « » »
tally6:. d = Count(iterable); return d
fait exactement, prend 60,0 msec
Vous pouvez regarder la source (collections.py dans le dépôt SVN) ... voici ce que mon Python27\Lib\collections.py
fait quand iterable
n'est pas une instance de mappage:
self_get = self.get
for elem in iterable:
self[elem] = self_get(elem, 0) + 1
Vous avez déjà vu ce code auparavant? Il y a beaucoup de bagage à main pour appeler du code exécutable en Python 1.5.2 :-O
Édition supplémentaire: Je cours la version 2.7. Aurait dû l'ajouter plus tôt! –
'Counter' ** est plus lent ** mais il a beaucoup plus de fonctionnalités que' defaultdict (int) '- voir ma réponse. –
pouvez-vous incrémenter plusieurs valeurs? – Mohsin