0

我想编写一个程序,从文本文件中读取字母,忽略符号和空格,并按从最常见到最不常见的顺序打印每个字母的计数。

另外,我正在为我的第一个编程课做这个,所以我不允许使用计数器。

到目前为止我有这个:

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

我使用的想法来自:

间谍

确定密文的字母频率

简单Z

python中的字母频率

4

5 回答 5

5

更新问题的解决方案

>>> 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
于 2012-04-14T03:28:15.570 回答
3

你可以这样做,

from operator import itemgetter
for k,v in sorted(occ.items(), key=itemgetter(1), reverse=True):
    print k, v

但是有更好的方法来计算字母,例如collections.Counter

于 2012-04-14T03:24:41.437 回答
1

既然你不能使用计数器,我会做这样的事情:

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
于 2012-04-14T03:48:35.647 回答
1

这是一个简单的 Python 版本,使用defaultdict(). 由于您说这是针对课程的,因此这并不是您要求的最终解决方案。

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 不会干扰早期排序的结果,除非它必须这样做。这意味着如果我们首先按字母顺序排序,然后按频率计数,那么对于频率计数相等的所有情况,我们将在该频率内获得字母顺序。因此,由于abc都是相同的频率(它们每个出现一次),您会期望部分输出为: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。这只计算那里的东西。

所以,我建议你重新编写这段代码。不要使用 a defaultdict,而是尝试使用普通的dict,但有一个循环将每个字母a设置zdict0 的计数。

我还建议,在您拥有dict包含您要计数的字母的普通代码后,您更改决定是否计数的代码。目前它使用.isalpha()方法函数来决定是否计算一个字符;相反,您可以检查该字符是否in是字典。然后,您可以使用此代码来计算标点符号或数字或任何类型的字符。

于 2012-04-14T03:55:25.073 回答
0

我认为更简单的方法是使用本机计数功能:

此代码仅打印每个字母的计数。您需要将其放入一个集合中并对其进行排序,以便首先获得最常见的字母。

text = 'Your original text.'
alpha = list ('abcdefghijklmnopqrstuvwxyz')
for letter in alpha:
    print letter + ': ' + str(text.count(letter))
于 2013-09-15T13:57:55.080 回答