1. 程式人生 > >python之統計字串中的字元個數

python之統計字串中的字元個數

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 = dict().fromkeys(keys,0
) #賦給每個key初始值0 new = [] #建立一個新列表用於存放有序的key st = st.lower() #將所有輸入的字元改為小寫 for s in st: #遍歷字串 di[s] = st.count(s) #輸出每個字元的個數,存放到字典裡 for k in keys: #遍歷keys,將其在di中的值新增到新列表,獲得有序的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函式然後又有遍歷迴圈的話會讓程式的執行很慢。。@weixin_42047817

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))