【发布时间】:2015-02-05 00:55:50
【问题描述】:
我正在 Reddit 上做这周的“简单”Daily Programmer Challenge。描述在链接上,但本质上的挑战是从 url 读取文本文件并进行字数统计。不用说,结果输出是一个相当大的字典对象。我有几个问题,主要是关于根据值访问或排序键。
首先,我根据我目前对 OOP 和良好 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
所以现在我有一个相当准确和强大的字数统计,可能没有任何重复或空白条目,但仍然是一个包含超过 3k 键/值对的 dict 对象。我无法使用 for k,v in count 对其进行迭代,或者它给了我异常 ValueError: too many values to unpack,它排除了使用列表推导或映射到函数来执行任何类型的排序。
几分钟前我正在阅读此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。呸!所以,我的问题是:
dict 甚至是执行原始计数的最佳数据类型吗?像
count.items()返回的元组列表会更好吗?但这可能会减慢速度,对吧?这似乎有点“笨拙”,因为我正在构建一个 dict,将其转换为包含元组的列表,然后对列表进行排序并返回一个新列表。但是,据我了解,字典允许我执行最快的查找,所以我在这里遗漏了什么吗?
我简要地阅读了有关散列的内容。虽然我认为我理解这一点是散列将节省内存空间并允许我执行更快的查找和比较,但权衡不会是程序变得计算成本更高(更高的 CPU 负载),因为它会然后计算每个单词的哈希值?散列在这里有用吗?
任何关于命名约定的反馈(我不擅长),或任何其他关于基本上任何事情(包括样式)的建议,将不胜感激。
【问题讨论】:
-
字典是存储 word:count 值的好方法。您可以通过执行
for k,v in count.iteritems()来迭代count。 -
CodeReview 是此类问题的最佳选择。与此同时,
collections.Counter可能会让您的事情变得更轻松。
标签: python sorting dictionary key-value counting