在Python中对计数列表排序
(我刚开始接触编程,所以请尽量具体一点来回答我)
问题:我写了一个程序来解决pythonchallenge.com的第二关。这个程序能工作,但结果看起来很乱。我想把字符计数的结果整理成一个好看的列表。当我尝试用sorted()来排序字符计数的结果时,它把所有的计数都去掉了,只给我一个包含我字符串中字符的列表。我需要能够看到每个字符在我的文件中出现了多少次。总之,这就是我的代码:
countstring = open('pagesource.txt').read()
charcount = {}
for x in countstring:
charcount[x] = charcount.get(x, 0) + 1
print charcount
这是我在命令行中得到的结果:
>>> {'\n': 1219, '!': 6079, '#': 6115, '%': 6104, '$': 6046, '&': 6043, ')': 6186, '
(': 6154, '+': 6066, '*': 6034, '@': 6157, '[': 6108, ']': 6152, '_': 6112, '^':
6030, 'a': 1, 'e': 1, 'i': 1, 'l': 1, 'q': 1, 'u': 1, 't': 1, 'y': 1, '{': 6046
, '}': 6105}
如果我加上一个sorted()函数,比如print sorted(charcount),我在命令行中得到的结果是:
>>> ['\n', '!', '#', '$', '%', '&', '(', ')', '*', '+', '@', '[', ']', '^', '_', 'a'
, 'e', 'i', 'l', 'q', 't', 'u', 'y', '{', '}']
谢谢你的解决方案,如果你能花时间在你的代码上加上注释,解释每一部分的作用,我会非常感激的!
6 个回答
字典(就是那个{}的意思)是无序的集合。这意味着你不能以任何有意义的方式对它们进行排序。我建议把信息存储为一个元组的列表 [(), ...],然后根据这个列表进行排序。
foo = [('a', 123), ('b', 345)]
def key_function(x):
return x[1]
sorted_list = sorted(foo, key_function)
print sorted_list
如你所见,sorted函数有一个可选的第二个参数。这个参数的作用是提供一个函数,告诉sorted如何进行排序。你所做的就是将列表中每个元组的信息拆分,提供一个可以排序的值,因为你实际上不能以任何有意义的方式对元组列表进行排序。
明白了吗?
它也可以写成:print sorted(foo, key=lambda (x,y): y)
lambda只是表示一个没有名字的内联函数,它允许你以不同的方式拆分元组。
你可以通过执行print [y for (x,y) in sorted_list]
来看看这个是怎么工作的。
你甚至可以像这样重新定义之前的key函数:
def key_function(x):
x,y = x
return y
顺便说一下,我在这里加上括号是为了让它更清楚。如果你不是在定义一个函数,那么逗号就是元组的构造器。
>>> from operator import itemgetter
>>> sorted(charcount.items(), key=itemgetter(1))
[('a', 1), ('e', 1), ('i', 1), ('l', 1), ('q', 1), ('u', 1), ('t', 1), ('y', 1), ('\n', 1219), ('^', 6030), ('*', 6034), ('&', 6043), ('$', 6046), ('{', 6046), ('+', 6066), ('!', 6079), ('%', 6104), ('}', 6105), ('[', 6108), ('_', 6112), ('#', 6115), (']', 6152), (' (', 6154), ('@', 6157), (')', 6186)]
当然可以!请把你想要翻译的内容发给我,我会帮你用简单易懂的语言解释清楚。
你真的应该使用Counter
这个类,而不是自己重新发明轮子。
charcount
是一个字典,而字典没有默认的排序顺序。所以,我们需要把它转换成一个可以排序的列表。这个列表中的每一项都会是一个元组,包含字符的数量和字符本身。
charcount.items()
已经给我们一个看起来像是[('\n', 1219), ('!', 6079)]
的列表。可惜的是,如果我们对这个列表进行排序,它会先按字符排序,然后(如果字符相同)再按数量排序,这样就不符合我们的需求了。因此,我们需要一个键函数,告诉排序先看数量,如果数量相同再看字符。幸运的是,我们的键函数非常简单,只需要调换元组中的位置:
lambda (char,count): (count, char)
另外,我们也可以使用列表推导式来调换值,得到类似[('\n', 1219), ('!', 6079)]
的东西,然后排序,再把值调换回来。
charcount_list = sorted(charcount.items(), key=lambda (char,count):(count, char))
现在,charcount_list
将变成:
[('a', 1), ('e', 1), ('i', 1), ('l', 1), ('q', 1), ('t', 1), ('u', 1), ('y', 1),
('\n', 1219), ('^', 6030), ('*', 6034), ('&', 6043), ('$', 6046), ('{', 6046),
('+', 6066), ('!', 6079), ('%', 6104), ('}', 6105), ('[', 6108), ('_', 6112),
('#', 6115), (']', 6152), (' (', 6154), ('@', 6157), (')', 6186)]
如果你想要反向排序,只需在sorted中指定reverse=True
参数即可。