今天在OpenHatch上找到一個(gè)涉及到很多Python知識(shí)點(diǎn)的問題接谨,這個(gè)問題寫著適于中級水平的Python程序員自測,需求是編寫一個(gè)帶評分功能的英文填字圖版游戲胧洒,我嘗試用2.7版本的Python對其進(jìn)行了編碼肌厨。
詳細(xì)需求:
practice breaking down a problem and solving it in Python from scratch
practice command line argument parsing
practice reading from files
practice working with dictionaries and for loops
翻譯作中文如下:
題中給了一個(gè)叫做sowpods.txt文件,這個(gè)文件中每一行是一個(gè)大寫單詞
用戶輸入一個(gè)單詞凰狞,通過運(yùn)行程序顯示這個(gè)單詞中的字母能組成的新單詞(小寫)
對于單詞中的字母篇裁,題目對每個(gè)字母給到一個(gè)數(shù)字分?jǐn)?shù),根據(jù)單詞中的字母得到的分?jǐn)?shù)進(jìn)行降序排序
sowpods.txt文件示意圖:
項(xiàng)目鏈接:
http://webcache.googleusercontent.com/search?q=cache:xcsq7ruu3NoJ:wiki.openhatch.org/Scrabble_challenge+&cd=9&hl=zh-CN&ct=clnk&gl=cn
如果你可以不看我的答案獨(dú)立解出這個(gè)問題赡若,相信你已經(jīng)是個(gè)不錯(cuò)的Python程序員了达布。
如果你有疑問,以下是我的詳細(xì)的思考編碼過程逾冬,也許你可以參考一下黍聂。
既然定義為中級水平,這個(gè)題目還是涉及到幾個(gè)知識(shí)點(diǎn)的身腻,我把我代碼中涉及到的Python知識(shí)點(diǎn)羅列了出來产还,如下:
1.文件操作
2.函數(shù)的使用
3.列表解析的應(yīng)用
4.Python的collections庫中Counter類的巧妙應(yīng)用
5.sys.argv取到用戶輸入的參數(shù)(個(gè)人選擇,用argparse庫效果類似)
...
構(gòu)思過程:
用面向函數(shù)的思想對這個(gè)問題進(jìn)行了解答。
程序分為5個(gè)函數(shù):
1.main
函數(shù)負(fù)責(zé)接受用戶參數(shù)嘀趟,調(diào)用其他函數(shù)雕沉,和對結(jié)果進(jìn)行排序(你也可以把接受函數(shù)和對結(jié)果排序獨(dú)立為兩個(gè)新函數(shù));
2.get_word_list
函數(shù)負(fù)責(zé)把sowpods
中的單詞放到一個(gè)list
中去件;
3.get_valid_words
函數(shù)篩選有效單詞并將其放在list
中返回坡椒;
4.lower_valid_words
函數(shù)負(fù)責(zé)把get_valid_words
函數(shù)變?yōu)樾?若你仔細(xì)做了這個(gè)題目,請?jiān)诹粞灾谢卮疬@個(gè)函數(shù)的好處)尤溜;
5.get_scores
函數(shù)負(fù)責(zé)計(jì)算每個(gè)單詞的分?jǐn)?shù)倔叼,并將結(jié)果存放在一個(gè)dict
中。
這個(gè)題目的難點(diǎn)在于get_valid_words
函數(shù)的編寫宫莱,最初我的思路是把用戶輸入的單詞
和
sowpods
中單詞的比較丈攒,說的具體一點(diǎn),當(dāng)我輸入helo
時(shí),程序輸出的結(jié)果是不可以出現(xiàn)hello
的巡验,因?yàn)?code>輸入單詞中l
的個(gè)數(shù)為1际插,而hello
中l
的個(gè)數(shù)為2,在首次編碼時(shí)显设,用list
對用戶輸入單詞進(jìn)行了存儲(chǔ)比較框弛,每當(dāng)找到一個(gè)單詞后就把list
中的對應(yīng)的字母移走,寫出來的代碼像這樣:
def get_valid_words(words, rack):
valid_words = []
for word in words:
rack_list = list(rack)
found = True
for c in word:
if c in rack_list:
rack_list.remove(c)
else:
found = False
break
if found:
valid_words.append(word)
return valid_words
后來我想到collections
中Counter
可以進(jìn)行加減運(yùn)算捕捂,可以大大簡化我的代碼瑟枫,而且提高代碼可讀性,更改后的代碼像下面這樣:
def get_valid_words(word_list, rack):
c = Counter(rack)
return [word for word in word_list if not (Counter(word) - c)]
參考資料鏈接:
https://pymotw.com/2/collections/counter.html
遺憾的是指攒,我對更改后的代碼進(jìn)行運(yùn)行測試慷妙,對于相同的用戶輸入單詞ZZAAEEI
,第一種函數(shù)運(yùn)行需要1.2s,而后一種寫法需要5.4s,這個(gè)問題我沒有細(xì)究允悦,有空我會(huì)看看Counter的源碼膝擂。
下面我貼出每個(gè)函數(shù):
1.main函數(shù)
def main():
if len(sys.argv) != 2:
raise SystemExit('Usage: scrabble_change.py RACK')
rack = sys.argv[1]
word_list = get_word_list('sowpods.txt')
valid_words = get_valid_words(word_list, rack.upper())
valid_words = lower_valid_words(valid_words)
d = get_scores(valid_words)
for val, key in sorted(zip(d.values(), d.keys()), reverse=True):
print(val, key)
2.get_word_list函數(shù)
def get_word_list(file_name):
word_list = []
with open(file_name) as f:
for line in f:
word_list.append(line.strip())
return word_list
3.get_valid_words函數(shù)
def get_valid_words(word_list, rack):
c = Counter(rack)
return [word for word in word_list if not (Counter(word) - c)]
4.lower_valid_words函數(shù)
def lower_valid_words(words):
return [word.lower() for word in words]
5.get_scores函數(shù)
def get_scores(words):
d = {}
for word in words:
d[word] = sum(scores[c] for c in word)
return d
以下是全部代碼,供參考:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
from __future__ import print_function
import sys
from collections import Counter
scores = {"a": 1, "c": 3, "b": 3, "e": 1, "d": 2, "g": 2,
"f": 4, "i": 1, "h": 4, "k": 5, "j": 8, "m": 3,
"l": 1, "o": 1, "n": 1, "q": 10, "p": 3, "s": 1,
"r": 1, "u": 1, "t": 1, "w": 4, "v": 4, "y": 4,
"x": 8, "z": 10}
def get_word_list(file_name):
word_list = []
with open(file_name) as f:
for line in f:
word_list.append(line.strip())
return word_list
def get_valid_words(word_list, rack):
c = Counter(rack)
return [word for word in word_list if not (Counter(word) - c)]
def lower_valid_words(words):
return [word.lower() for word in words]
def get_scores(words):
d = {}
for word in words:
d[word] = sum(scores[c] for c in word)
return d
def main():
if len(sys.argv) != 2:
raise SystemExit('Usage: scrabble_change.py RACK')
rack = sys.argv[1]
word_list = get_word_list('sowpods.txt')
valid_words = get_valid_words(word_list, rack.upper())
valid_words = lower_valid_words(valid_words)
d = get_scores(valid_words)
for val, key in sorted(zip(d.values(), d.keys()), reverse=True):
print(val, key)
if __name__ == '__main__':
main()
運(yùn)行效果圖:
總結(jié):
除了上面指出的知識(shí)點(diǎn)隙弛,本程序函數(shù)的命名也符合<代碼整潔之道>的規(guī)范猿挚,本程序遵守PEP8規(guī)范,若有錯(cuò)誤驶鹉,請大家勘正绩蜻。
歡迎各位指出這個(gè)程序可以改進(jìn)的地方!