На этой неделе я участвую в "легком" Ежедневном испытании программистов на Reddit. . Описание находится по ссылке, но по сути задача состоит в том, чтобы прочитать текстовый файл по URL-адресу и подсчитать количество слов. Излишне говорить, что в результате получается довольно большой объект словаря. У меня есть несколько вопросов, в основном касающихся доступа или сортировки ключей по их значению.
Во-первых, я разработал код в соответствии с тем, что я сейчас понимаю в ООП и хорошем стиле Python. Я хотел, чтобы он был как можно более надежным, но также хотел использовать как можно меньше импортированных модулей. Моя цель - стать хорошим программистом, поэтому я считаю, что важно заложить прочный фундамент и понять, как делать что-то самому, когда это возможно. При этом код:
from urllib2 import urlopen
class Word(object):
def __init__(self):
self.word_count = {}
def alpha_only(self, word):
"""Converts word to lowercase and removes any non-alphabetic characters."""
x = ''
for letter in word:
s = letter.lower()
if s in 'abcdefghijklmnopqrstuvwxyz':
x += s
if len(x) > 0:
return x
def count(self, line):
"""Takes a line from the file and builds a list of lowercased words containing only alphabetic chars.
Adds each word to word_count if not already present, if present increases the count by 1."""
words = [self.alpha_only(x) for x in line.split(' ') if self.alpha_only(x) != None]
for word in words:
if word in self.word_count:
self.word_count[word] += 1
elif word != None:
self.word_count[word] = 1
class File(object):
def __init__(self,book):
self.book = urlopen(book)
self.word = Word()
def strip_line(self,line):
"""Strips newlines, tabs, and return characters from beginning and end of line. If remaining string > 1,
splits up the line and passes it along to the count method of the word object."""
s = line.strip('\n\r\t')
if s > 1:
self.word.count(s)
def process_book(self):
"""Main processing loop, will not begin processing until the first line after the line containing "START".
After processing it will close the file."""
begin = False
for line in self.book:
if begin == True:
self.strip_line(line)
elif 'START' in line:
begin = True
self.book.close()
book = File('http://www.gutenberg.org/cache/epub/47498/pg47498.txt')
book.process_book()
count = book.word.word_count
Итак, теперь у меня есть довольно точный и надежный подсчет слов, который, вероятно, не имеет дубликатов или пустых записей, но, тем не менее, является объектом dict, содержащим более 3k пар ключ / значение. Я не могу перебирать его, используя for k,v in count
, или это дает мне исключение ValueError: too many values to unpack
, которое исключает использование понимания списка или сопоставления с функцией для выполнения любого вида сортировки.
Я читал это HowTo on Sorting" rel="nofollow"> HowTo on Sorting и играл с ним несколько минут назад и заметил, что for x in count.items()
позволяет мне перебирать список пар ключ / значение, не вызывая исключения ValueError, поэтому я удалил строку count = book.word.word_count
и добавил следующее:
s_count = sorted(book.word.word_count.items(), key=lambda count: count[1], reverse=True)
# Delete the original dict, it is no longer needed
del book.word.word_count
Теперь у меня наконец-то есть отсортированный список слов s_count
. PHEW! Итак, мои вопросы:
Является ли dict лучшим типом данных для первоначального подсчета? Может ли быть предпочтительнее список кортежей, подобных тому, который возвращается
count.items()
? Но это, вероятно, замедлит его, не так ли?Это кажется «неуклюжим», поскольку я создаю dict, конвертирую его в список, содержащий кортежи, затем сортирую список и возвращаю новый список. Однако, насколько я понимаю, словари позволяют мне выполнять самый быстрый поиск, так что я что-то здесь упускаю?
Я прочитал кратко о хешировании. Хотя я думаю, что понимаю, что суть в том, что хеширование позволит сэкономить место в памяти и позволит мне выполнять более быстрые поиски и сравнения, не будет ли компромисс в том, что программа станет более затратной в вычислительном отношении (более высокая загрузка ЦП), потому что это будет тогда будет вычислять хеши для каждого слова? Здесь уместно хеширование?
Мы будем очень благодарны за любые отзывы о соглашениях об именах (в которых я ужасен) или любые другие предложения практически обо всем (включая стиль).
count
, выполнивfor k,v in count.iteritems()
. - person all or None   schedule 07.12.2014collections.Counter
может упростить вам задачу. - person wwii   schedule 07.12.2014