我想编写一个程序,从文本文件中读取字母,忽略符号和空格,并按照从最常见到最不常见的顺序打印每个字母的计数。
另外,我正在为第一个编程课程工作,所以我不允许使用计数器。
到目前为止,我有这个:
name= raw_input("Enter file name:")
fl= open(name, 'r+').read()
lw= fl.lower()
ws= lw.replace(' ','')
sm= ws.translate(None, ",-!.;?:")
occ= {}
alpha= list ('abcdefghijklmnopqrstuvwxyz')
for x in alpha:
occ[x]= sm.count(x)
for x in occ:
print x, occ[x]
假装文本文件是这样的:“我对此感到非常困惑?”
然后程序将通过它的编程并执行此操作:“iamhighlyconfusedbythis”
但是现在它只显示这样的东西:
1 a
1 b
1 c
1 d
1 e
1 f
1 g
3 h
3 i
0 j
0 k
1 l
1 m
1 n
1 o
0 p
0 q
0 r
2 s
1 t
1 u
0 v
0 w
0 x
2 y
0 z
但我希望结果如下:
3 h
3 i
2 s
2 y
1 e
1 f
1 g
1 a
1 b
1 l
1 m
1 n
1 o
1 c
1 t
1 u
1 d
0 j
0 k
0 p
0 q
0 r
0 v
0 w
0 x
0 z
我使用了以下的想法:
spyshyguy
Determining Letter Frequency Of Cipher Text
SimplyZ
答案 0 :(得分:4)
更新问题的解决方案
>>> from collections import defaultdict
>>> import string
>>> text = 'I am highly confused by this?'.lower().translate(None,string.punctuation+' ')
>>> c = defaultdict(int)
>>> c.update({letter:0 for letter in string.lowercase[:26]}) #Initialize each letter of alphabet to 0
>>> for letter in text:
c[letter] += 1
>>> for letter,freq in sorted(c.iteritems(),key=lambda (l,f): (-f,l)): #Sort by frequency in descending order by making frequency negative then by letter in ascending order
print freq, letter
3 h
3 i
2 s
2 y
1 a
1 b
1 c
1 d
1 e
1 f
1 g
1 l
1 m
1 n
1 o
1 t
1 u
0 j
0 k
0 p
0 q
0 r
0 v
0 w
0 x
0 z
解决原始问题:
您可以使用collections.Counter
:
>>> from collections import Counter
>>> import string
>>> text = 'I am highly confused by this?'.translate(None,string.punctuation+' ')
>>> print ' '.join('%d %s'%(freq,letter) for letter,freq in Counter(x).most_common())
3 h 2 i 2 s 2 y 1 a 1 c 1 b 1 e 1 d 1 g 1 f 1 I 1 m 1 l 1 o 1 n 1 u 1 t
答案 1 :(得分:3)
你可以这样做,
from operator import itemgetter
for k,v in sorted(occ.items(), key=itemgetter(1), reverse=True):
print k, v
但是有更好的方法来计算字母,例如collections.Counter
答案 2 :(得分:1)
由于你不能使用Counter,我会做这样的事情:
from string import ascii_lowercase
with open(name, 'r') as f:
raw_text = f.read().lower()
letterCounts = [raw_text.count(letter) for letter in ascii_lowercase]
frequencies = reversed(sorted(zip(ascii_lowercase, letterCounts), lambda x: x[1]))
for i in frequencies:
print "%s: %d" % i
答案 3 :(得分:0)
这是一个使用defaultdict()
的简单Python版本。既然你说这是一个类,这不是你要求的最终解决方案。
from collections import defaultdict
from operator import itemgetter
d = defaultdict(int)
name = raw_input("Enter file name: ")
with open(name, "r") as f:
for line in f:
for ch in line:
if ch.isalpha():
d[ch] += 1
lst = d.items()
# sort twice: once for alphabetical order, then for frequency (descending).
# Because the Python sort is "stable", we will end up with descending
# frequency, but alphabetical order for any frequency values that are equal.
lst.sort(key=itemgetter(0))
lst.sort(key=itemgetter(1), reverse=True)
for key, value in lst:
print value, key,
当您在打开的文件上执行for循环时,例如此处的for line in f
,Python将从输入文件中一次抓取一行。然后我们在输入行上一次循环一个字符。然后我们检查它是否是一个字母,如果是,我们增加字母的频率计数。
此代码中存在错误。你希望它计算所有字母的频率,好像它们都是小写字母一样,但是这个代码将保留一个大写的计数和另一个小写的计数。我相信你可以弄清楚如何修改它,以便计数只适用于小写。
完成计数后,我们使用.items()
方法函数获取(key, value)
元组的列表。例如:('h', 3)
是一个元组,其中包含字典键字符h
及其值,即计数3。
现在我们要排序。我向你展示了Python可以做的一个很好的技巧:因为排序是一种“稳定”排序,如果我们做多种排序,Python不会干扰早期排序的结果,除非它必须。这意味着如果我们首先按字母顺序排序,然后然后按频率计数排序,那么对于频率计数相等的所有情况,我们将在该频率内获得字母顺序。因此,由于a
,b
和c
都是相同的频率(它们各自出现一次),您可能希望输出的一部分为:1 a 1 b 1 c
现在,我有点棘手,但这很好学。 sort函数可以使用一个名为key
的参数来控制排序。 key
应该是一个返回要用于排序的值的函数。由于我们有一个元组列表,我们需要一个关键函数,它可以获取元组的一部分并返回它。我们可以编写两个函数:
def get_key(kv_tuple):
return kv_tuple[0]
def get_value(kv_tuple):
return kv_tuple[1]
但Python有一个函数operator.itemgetter()
,我们可以使用它。如果我们只是告诉它我们想要得到的元组中的哪个位置,它将为我们提供一个关键功能,它将为我们提供元组的一部分。
由于我们希望首先按最大值对频率进行排序,因此我们还在reverse=True
方法的参数中设置.sort()
。
最后,我们遍历键,值元组和打印列表。
此代码中还有另一个问题。您的示例输出显示您希望每个字母都在列表中,如果字母不在输入中,则计数为0。这只计算那里的东西。
所以,我建议你重新编写这段代码。不要使用defaultdict
,而是尝试使用普通dict
,但要设置一个循环,将每个字母a
设置为z
到dict
数为0.
我还建议,在您的普通dict
包含您要计算的字母后,您可以更改决定是否计算的代码。目前,它使用.isalpha()
方法函数来决定是否计算一个字符;相反,您可以检查该字符是否为in
字典。然后,您可以使用此代码来计算标点符号或数字或任何类型的字符。
答案 4 :(得分:0)
我认为更简单的方法是使用本机计数功能:
此代码只打印每个字母的计数。你需要把它放在一个集合中,并为你排序,以便先获得最常用的字母。
text = 'Your original text.'
alpha = list ('abcdefghijklmnopqrstuvwxyz')
for letter in alpha:
print letter + ': ' + str(text.count(letter))