执行计数,排序/映射大型字典
我正在做这个星期在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('nrt')
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键/值对的字典对象。 我无法for k,v in count
使用for k,v in count
来迭代它for k,v in count
或者它给了我异常的ValueError: too many values to unpack
,这些ValueError: too many values to unpack
使用列表理解或映射到函数来执行任何类型的排序。
我在几分钟前阅读了关于排序和播放的HowTo,并注意到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
。 唷! 所以,我的问题是:
是字典甚至是执行原始计数的最佳数据类型? 像count.items()
返回的元组列表是否会更可取? 但是这可能会减慢速度,对吧?
这似乎有点“笨重”,因为我正在构建一个字典,将其转换为包含元组的列表,然后对列表进行排序并返回一个新列表。 但是,我的理解是词典允许我执行最快的查找,所以我在这里错过了什么?
我简要地读了哈希。 虽然我认为我的理解是,散列会节省内存空间,并允许我执行更快速的查找和比较,但不会因为程序的计算成本更高(CPU负载更高)然后为每个单词计算哈希值? 哈希与此有关吗?
任何关于命名约定(我很可怕)的反馈,或任何其他有关基本上任何东西(包括样式)的建议,都将不胜感激。
你确定for k,v in count:
给出异常ValueError: too many values to unpack
? 我期望它会给ValueError: need more than 1 value to unpack
。
当你使用一个dict
作为一个迭代器时(例如在for
循环中),你只需要得到这些键,就不会得到这些值。 如果你想要键值对,你需要使用dict
的iteritems()
方法,如注释中的无花果(或Python 3中的items()
方法)所述。
当然,你总是可以做一些事情:
for k in count:
print k, count[k]
...
我认为你的大多数问题更适合Code Review而不是Stack Overflow。 但是既然你在这里问得很好,我会提几点。 :)
用char构建一个字符串的效率相当低,所以如果alpha_only()
方法在列表中收集字符,然后使用str.join()
方法将它们连接成单个字符串,那么alpha_only()
会更好。 通常的Python成语会使用列表理解来做到这一点。
count()
方法中的列表理解为每个单词调用alpha_only()
两次,这是有效的。
您可以使用默认参数使strip()
调用更简单,因为这会剥离所有空格(并且不需要在此应用程序中保留空格字符)。 类似地,使用split()
及其默认参数arg将会在任何空白空间上分割,这在本应用中可能会更好,因为给出单个空间的arg意味着在分割返回的列表中会得到一些空字符串如果一行中有多个空格的运行。
...
你在你的问题中提到了哈希,以及它对这个应用程序是否有用。 是的。 Python字典实际上使用他们的密钥散列,所以你不需要担心细节。 是的,字典是一个很好的数据结构,可用于此任务。 字典有很多形式,使事情变得更简单,但使用它们需要导入(标准)模块。 但是使用一个字典(某种风格或另一种风格)来保存数据,然后从中产生一个元组列表来进行最终的排序,这在Python中是相当普遍的做法。 如果程序即将终止,则无需在完成时专门删除字典。
...
至于alpha_only()
的重复调用,每当你发现自己在做这样的事情时,这是一个迹象表明,列表理解不适合该任务,并且你应该使用一个正常的for
循环,这样你就可以保存函数调用的结果,而不必重新计算它。 例如,
words = []
for word in line.split():
word = self.alpha_only(word)
if word is not None:
words.append(word)
链接地址: http://www.djcxy.com/p/76637.html