Вы спрашивали, какая из них была более эффективной. Предполагая, что вы говорите о скорости выполнения: если ваши данные малы, это не имеет значения. Если он большой и типичный, случай «уже существует» будет происходить гораздо чаще, чем случай «не в dict». Это наблюдение объясняет некоторые результаты.
Ниже приведен код, который может использоваться с модулем timeit
для изучения скорости без накладных расходов на чтение файлов. Я взял на себя смелость добавить 5-й метод, который не является неконкурентоспособным и будет работать на любом Python по меньшей мере с 1.5.2 [проверено] и далее.
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
Типичный пробег (в Windows XP "Командная строка" окно):
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
Вот результаты (мсек на петле):
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
Другое испытание времени:
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
Скорость Counter
, возможно, из-за того, что он частично реализован в коде Python, тогда как defaultdict
полностью находится в C (по крайней мере, в 2.7).
Обратите внимание, что Counter()
это не просто «синтаксический сахар» для defaultdict(int)
- он реализует полный bag
аки multiset
объекта - см документации для деталей; они могут спасти вас от переосмысления колеса, если вам нужна какая-то причудливая постобработка. Если все, что вы хотите сделать, это подсчитать, используйте defaultdict
.
Update в ответ на вопрос @Steven Rumbalski: «»»Мне любопытно, что произойдет, если вы переместите итерацию в конструктор счетчика: d = Счетчик (итерацию) (У меня есть Python 2.6 и не может проверить его) «»»
tally6:. просто делает d = Count(iterable); return d
, занимает 60,0 мсек
Вы можете посмотреть на источник (collections.py в хранилище SVN) ... вот что мой Python27\Lib\collections.py
делает, когда iterable
не является экземпляром сопоставления:
self_get = self.get
for elem in iterable:
self[elem] = self_get(elem, 0) + 1
Видел, что код где-нибудь раньше? Существует много операций, чтобы вызвать код, который можно использовать в Python 1.5.2 :-O
Дополнительная редакция: Я запускаю версию 2.7. Должен добавить это раньше! –
'Counter' ** медленнее ** однако он имеет гораздо больше функциональности, чем' defaultdict (int) '- см. Мой ответ. –
Вы можете увеличить несколько значений? – Mohsin