Лучший способ подсчитать число символов в строке - PullRequest
5 голосов
/ 21 января 2012

Здравствуйте, я пытаюсь записать эти строки Python в одну строку, но получаю некоторые ошибки из-за изменений в словаре, которые делает код.

for i in range(len(string)):
    if string[i] in dict:
        dict[string[i]] += 1

Общий синтаксис, который я считаю,

abc = [i for i in len(x) if x[i] in array]

Может ли кто-нибудь сказать мне, как это может работать, учитывая, что я добавляю 1 к значению в словаре

Спасибо

Ответы [ 6 ]

7 голосов
/ 21 января 2012

Альтернатива для Python 2.7 +:

from collections import Counter

abc = Counter('asdfdffa')
print abc
print abc['a']

Выход:

Counter({'f': 3, 'a': 2, 'd': 2, 's': 1})
2
7 голосов
/ 21 января 2012

То, что вы пытаетесь сделать, можно сделать с помощью dict, выражения генератора и str.count():

abc = dict((c, string.count(c)) for c in string)

Альтернатива с использованием set(string) (из комментария внизу soulcheck) :

abc = dict((c, string.count(c)) for c in set(string))

Сроки

При просмотре комментариев внизу я провел небольшое тестирование среди этого и других ответов. (с python-3.2)

Функции тестирования:

@time_me
def test_dict(string, iterations):
    """dict((c, string.count(c)) for c in string)"""
    for i in range(iterations):
        dict((c, string.count(c)) for c in string)

@time_me
def test_set(string, iterations):
    """dict((c, string.count(c)) for c in set(string))"""
    for i in range(iterations):
        dict((c, string.count(c)) for c in set(string))

@time_me
def test_counter(string, iterations):
    """Counter(string)"""
    for i in range(iterations):
        Counter(string)

@time_me
def test_for(string, iterations, d):
    """for loop from cha0site"""
    for i in range(iterations):
        for c in string:
            if c in d:
                d[c] += 1

@time_me
def test_default_dict(string, iterations):
    """defaultdict from joaquin"""
    for i in range(iterations):
        mydict = defaultdict(int)
        for mychar in string:
            mydict[mychar] += 1

Выполнение теста:

d_ini = dict((c, 0) for c in string.ascii_letters)
words = ['hand', 'marvelous', 'supercalifragilisticexpialidocious']

for word in words:
    print('-- {} --'.format(word))
    test_dict(word, 100000)
    test_set(word, 100000)
    test_counter(word, 100000)
    test_for(word, 100000, d_ini)
    test_default_dict(word, 100000)
    print()

print('-- {} --'.format('Pride and Prejudcie - Chapter 3 '))

test_dict(ch, 1000)
test_set(ch, 1000)
test_counter(ch, 1000)
test_for(ch, 1000, d_ini)
test_default_dict(ch, 1000)

Результаты испытаний:

-- hand --
389.091 ms -  dict((c, string.count(c)) for c in string)
438.000 ms -  dict((c, string.count(c)) for c in set(string))
867.069 ms -  Counter(string)
100.204 ms -  for loop from cha0site
241.070 ms -  defaultdict from joaquin

-- marvelous --
654.826 ms -  dict((c, string.count(c)) for c in string)
729.153 ms -  dict((c, string.count(c)) for c in set(string))
1253.767 ms -  Counter(string)
201.406 ms -  for loop from cha0site
460.014 ms -  defaultdict from joaquin

-- supercalifragilisticexpialidocious --
1900.594 ms -  dict((c, string.count(c)) for c in string)
1104.942 ms -  dict((c, string.count(c)) for c in set(string))
2513.745 ms -  Counter(string)
703.506 ms -  for loop from cha0site
935.503 ms -  defaultdict from joaquin

# !!!: Do not compare this last result with the others because is timed
#      with 1000 iterations instead of 100000
-- Pride and Prejudcie - Chapter 3  --
155315.108 ms -  dict((c, string.count(c)) for c in string)
982.582 ms -  dict((c, string.count(c)) for c in set(string))
4371.579 ms -  Counter(string)
1609.623 ms -  for loop from cha0site
1300.643 ms -  defaultdict from joaquin
6 голосов
/ 21 января 2012

Это задание для модуля коллекций:


Опция 1 .- коллекций.defaultdict :

>>> from collections import defaultdict
>>> mydict = defaultdict(int)

, тогда ваш цикл становится следующим:

>>> for mychar in mystring: mydict[mychar] += 1

Опция 2.collection.Counter (из комментария Феликса):

Альтернатива, которая лучше для этого конкретного случая, и из того же модуля collections:

>>> from collections import Counter

вам нужно только (!!!):

>>> mydict = Counter(mystring)

Счетчик доступен только в Python 2.7.Так что для python <2.7 вы должны остаться с defaultdict </p>

1 голос
/ 21 января 2012

Это не хороший кандидат для понимания списка.Обычно вы хотите использовать списочные выражения для составления списка, и иметь побочные эффекты (изменение глобальных состояний) в них не очень хорошая идея.

С другой стороны, ваш код может быть лучше, как этот:

for c in string:
    if c in dict:
        dict[c] += 1

Или, если вы действительно хотите получить функциональность (я переименовал dict в d, потому что мне нужна встроенная функция python dict):

d.update(dict([ (c, d[c]+1, ) for c in string ]))

Обратите внимание, как я не изменил d в пределах понимания списка, а вместо этого обновил d вне его.

0 голосов
/ 26 июня 2014
>>> def count(s):
    global k
    list =[]
    for i in s:
        k=0
        if i not in list:
            list.append(i)      
            for j in range(len(s)):
                if i == s[j]:
                    k +=1

            print 'count of char {0}:{1}'.format(i,k)


>>> count('masterofalgorithm')
count of char m:2
count of char a:2
count of char s:1
count of char t:2
count of char e:1
count of char r:2
count of char o:2
count of char f:1
count of char l:1
count of char g:1
count of char i:1
count of char h:1
>>> 
0 голосов
/ 21 января 2012

Ваш оригинальный цикл безнадежно пифоничен. Нет необходимости перебирать range(len(string)), если все, что вам нужно, это перебирать буквы в string. Сделайте это вместо:

for c in my_string:
    if c in my_dict:
        my_dict[c] += 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...