1.贴题
题目来自MOOC
《用Python玩转数据》(南京大学)
第三周编程作业
定义函数countchar()按字母表顺序统计字符串中所有出现的字母的个数(允许输入大写字符,并且计数时不区分大小写)。形如:
def countchar(str):
... ...
return a list
if __name__ == "__main__":
str = input()
... ...
print(countchar(str))
输入格式:
字符串
输出格式:
列表
输入样例:
Hello, World!
输出样例:
[0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 3, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0]
时间限制:500ms内存限制:32000kb
2.说明
这道题确实费了一些功夫。
思路为以字母为key,出现次数为value建立字典,然后根据输入的字符串调用函数输出value值。(此处有一个坑,在后面说明)。
3.参考代码
def countchar(st): #定义数个数的函数
keys = [chr(i+97) for i in range(26)] #生成26个字母的key列表
di = {}.fromkeys(keys,0) #赋给每个key初始值0
new = [] #建立一个新列表用于存放有序的key
st = st.lower() #将所有输入的字符改为小写
for s in st: #遍历字符串
di[s] = st.count(s) #输出每个字符的个数,存放到字典里
for k in di: #遍历字典
if k in keys: #如果key出现在26个字母中,则将其值添加到新列表,获得有序的26个字母的个数
new.append(di[k])
return new #返回存有26个字母个数的列表
if __name__ == "__main__":
st = input() #输入字符串
str1 = "" #定义一个空字符串
for s in st: #遍历输入的字符串
if s.isalpha() != 0: #只有字母才添加到新字符串,标点忽略不计
str1 += s
print(countchar(str1)) #输出列表
4.代码的注意点
生成26个字母的代码一开始没想到要怎么写,直接手写的
keys=["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
然后遭到了吐槽。。
命名dict的时候直接使用了dict,使用了python的保留字,虽然没有出错,但是还是遭到了无情的吐槽。。
- 赋给每个元素初值的时候不记得具体怎么写了,查资料找到了通过fromkeys设置多个键的值
- 巩固了将所有字符改为小写的写法 str.lower()
- 实际使用了字符串的count函数 str.count(要数的字符或字符串)
- 字典的key在字典里面的排序是无序的,因为没有注意到这一点,刚开始的代码是错的,因为输出来的列表顺序不对,请教了才修改正确的,增加了遍历然后添加到新列表的代码
- 无视标点既可以创建一个含有各种特殊字符的字符串然后使用remove函数,如果只要求计数字母(或者只计数字)的时候,就可以使用专门的isalpha或者isdigit函数。相关资料Python isalpha()方法
- 还有就是被吐槽使用count函数然后又有遍历循环的话会让程序的执行很慢。。
5.更好的代码
参考了以下几篇人家的博客
把代码修改为如下
def countchar(str):
alist = []
for i in range(26): #初始化一个长度为26,值均为0的列表
alist.append(0)
str = str.lower()
for i in str: #遍历字符串,如果是字母,则利用ascii码值转换为数字再平移至0-26范围内,将对应的列表值加一
if i.isalpha():
alist[ord(i)-97] += 1
return alist
if __name__ == "__main__": #主函数部分与原代码相同
st = input()
str1 = ""
for s in st:
if s.isalpha() != 0:
str1 += s
print(countchar(str1))
6.代码执行速度
在要统计的字符串为
st = "".join([chr(i+96)*i*100 for i in range(1,27)])
时,3的代码和5的代码的执行速度结果如下
3代码
[100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600]
time: 1.108361 s
5代码
[100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600]
time: 0.023698 s
确实速度相差50倍多啊。。
附3代码测试代码
import time
def countchar(st):
keys = [chr(i+97) for i in range(26)]
di = {}.fromkeys(keys,0)
new = []
st = st.lower()
for s in st:
di[s] = st.count(s)
for k in di:
if k in keys:
new.append(di[k])
return new
if __name__ == "__main__":
st = "".join([chr(i+96)*i*100 for i in range(1,27)])
str1 = ""
start = time.clock()
for s in st:
if s.isalpha() != 0:
str1 += s
print(countchar(str1))
end = time.clock()
print("time: %f s" % (end - start))
7.最后存档错误代码
下面的代码是不正确的!!!
错误原因(没有考虑到字典内部存储的时候是无序的)
def countchar(st):
keys = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
dict = {}.fromkeys(keys,0)
st = st.lower()
for s in st:
dict[s] = st.count(s)
return list(dict.values())
if __name__ == "__main__":
st = input()
str1 = ""
for s in st:
if s.isalpha() != 0:
str1 += s
print(countchar(str1))