美化你LeetCode倉庫的README

LeetCode幾乎成了現在每個人找工作前都要刷的"新手村"的怪,每一個找工作的人面試之前都要都會去刷一刷。閑話不多說,先看看大佬們都是怎麼評價LeetCode, zhihu.com/question/2624

雖然面試官也不會看你github上leetcode的repo,但是如果你有這麼一個東西還是極好的,很多大佬都會去刷這個東西,放在github上面,當然新手也會這麼做。我們就會發現,大佬們的README超級好看,方便自己日後查找,但是新手的命名就比較雜亂無章,一點也不規範,自己找起來非常費勁。我自己就是這麼一個情況,所以我決定重構一下這個目錄結構,生成一個好看一點的。

我們先看一下生成的效果吧!更詳細具體效果請查看這裡

直接上操作部分吧!

前期準備

在github上創建一個倉庫,比如叫leetcode或者像我的一樣叫algorithms_and_oj。然後從github中git clone下來。

然後,安裝項目前置需要的庫:

pip install requests

開始分析

首先需要配置我們的路徑 (以下路徑均按照我項目來配置,需要按照自己要求修改)

class Config: """ some config, such as your github page 這裡需要配置你自己的項目地址 1. 本地倉庫的的路徑 2. github中的倉庫leetcode解法的路徑 """ local_path = /home/yuan/PycharmProjects/algorithms_and_oj # solution of leetcode github_leetcode_url = https://github.com/hey-bruce/algorithms_and_oj/blob/master/leetcode-algorithms/ # solution of pat, 暫時還沒用上 github_pat_url = https://github.com/hey-bruce/algorithms_and_oj/blob/master/pat-algorithms/ leetcode_url = https://leetcode.com/problems/

我們需要哪些信息,每個問題的ID,title, url,難度,已經使用什麼語言解決等,所以我們很自然的構造一個Question類

class Question: """ this class used to store the inform of every question """ def __init__(self, id_, name, url, lock, difficulty): self.id_ = id_ self.title = name # the problem description url 問題描述頁 self.url = url self.lock = lock # boolean,鎖住了表示需要購買 self.difficulty = difficulty # the solution url self.python = self.java = self.javascript = self.c_plus_plus = def __repr__(self): """ 沒啥用,我為了調試方便寫的 :return: """ return str(self.id_) + + str(self.title) + + str(self.url)

接下來,我們就要從LeetCode上獲取問題,在在google一查,就找到了leetcode.com/api/proble返回的是json數據。稍微進行了一下分析(這個自己看一下數據,很容易發現的,雖然leetcode沒有api描述頁),就可以知道stat中的frontend_question_ididquestion__title_slug對應的url的地址,question__title對應的是問題的名字,paid_only表示是否需要購買。difficulty表示難度.。然後我們可以出獲取LeetCode信息的代碼。

def get_leetcode_problems(self): """ used to get leetcode inform :return: """ # we should look the response data carefully to find law # return byte. content type is byte content = requests.get(https://leetcode.com/api/problems/algorithms/).content # get all problems self.questions = json.loads(content)[stat_status_pairs] # print(self.questions) difficultys = [Easy, Medium, Hard] for i in range(len(self.questions) - 1, -1, -1): question = self.questions[i] name = question[stat][question__title] url = question[stat][question__title_slug] id_ = str(question[stat][frontend_question_id]) if int(id_) < 10: id_ = 00 + id_ elif int(id_) < 100: id_ = 0 + id_ lock = question[paid_only] if lock: self.locked += 1 difficulty = difficultys[question[difficulty][level] - 1] url = Config.leetcode_url + url + /description/ q = Question(id_, name, url, lock, difficulty) # 這裡後面我們會放到類裡面,所以不用擔心 # 之所以用一個table和table_item就是因為,我們後期已經用什麼語言解決題目的時候要進行索引 self.table.append(q.id_) self.table_item[q.id_] = q return self.table, self.table_item

我們需要一個東西記錄我們完成情況的類CompleteInform:

class CompleteInform: """ this is statistic inform, 用每種語言完成了多少題 """ def __init__(self): self.solved = { python: 0, c++: 0, java: 0, javascript: 0 } self.total = 0 def __repr__(self): return str(self.solved)

然後我們根據題目信息來建立題目對應的文件夾,

def __create_folder(self, oj_name): """ oj_name後面會傳入leetcode,這裡這麼做就是後期,我想擴展生成別的oj的table """ oj_algorithms = Config.local_path + / + oj_name + -algorithms if os.path.exists(oj_algorithms): print(oj_name, algorithms is already exits) else: print(creating {} algorithms.....format(oj_name)) os.mkdir(oj_algorithms) for item in self.table_item.values(): question_folder_name = oj_algorithms + / + item.id_ + . + item.title if not os.path.exists(question_folder_name): print(question_folder_name + is not exits, create it now....) os.mkdir(question_folder_name)# 這裡都會傳入一個『leetcode,設置oj名字就是為了方便擴展def update_table(self, oj): # the complete inform should be update complete_info = CompleteInform() self.get_leetcode_problems() # the total problem nums complete_info.total = len(self.table) self.__create_folder(oj) oj_algorithms = Config.local_path + / + oj + -algorithms # 查看os.walk看具體返回的是什麼東西 for _, folders, _ in os.walk(oj_algorithms): for folder in folders: for _, _, files in os.walk(os.path.join(oj_algorithms, folder)): if len(files) != 0: complete_info.complete_num += 1 for item in files: if item.endswith(.py): # 這個部分可以寫成函數,不過我好像設計有點問題,不太好重構,請讀者自己思考 complete_info.solved[python] += 1 folder_url = folder.replace( , "%20") folder_url = os.path.join(folder_url, item) folder_url = os.path.join(Config.github_leetcode_url, folder_url) self.table_item[folder[:3]].python = [python]({}).format(folder_url) elif item.endswith(.java): complete_info.solved[java] += 1 folder_url = folder.replace( , "%20") folder_url = os.path.join(folder_url, item) folder_url = os.path.join(Config.github_leetcode_url, folder_url) self.table_item[folder[:3]].java = [Java]({}).format(folder_url) elif item.endswith(.cpp): complete_info.solved[c++] += 1 folder_url = folder.replace( , "%20") folder_url = os.path.join(folder_url, item) folder_url = os.path.join(Config.github_leetcode_url, folder_url) self.table_item[folder[:3]].c_plus_plus = [C++]({}).format(folder_url) elif item.endswith(.js): complete_info.solved[javascript] += 1 folder_url = folder.replace( , "%20") folder_url = os.path.join(folder_url, item) folder_url = os.path.join(Config.github_leetcode_url, folder_url) self.table_item[folder[:3]].javascript = [JavaScript]({}).format(folder_url) # 這裡使用到的Readme這個類就是寫文件,相對不是特別重要,沒什麼好講的 readme = Readme(complete_info.total, complete_info.complete_num, complete_info.solved) readme.create_leetcode_readme([self.table, self.table_item]) print(-------the complete inform-------) print(complete_info.solved)

上面需用用到的Readme類,用來生成README.md,只是進行了文件的讀寫,相對比較簡單。聰明的你肯定一看就知道了。(只需要了解一點markdown中表格的生成規則)

class Readme: """ generate folder and markdown file update README.md when you finish one problem by some language """ def __init__(self, total, solved, others): """ :param total: total problems nums :param solved: solved problem nums :param others: 暫時還沒用,我想做擴展 """ self.total = total self.solved = solved self.others = others self.time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) self.msg = # Keep thinking, keep alive
Until {}, I have solved **{}** / **{}** problems.

Completion statistic:
1. JavaScript: {javascript}
2. Python: {python}
3. C++: {c++}
4. Java: {java}

Note: :lock: means you need to buy a book from LeetCode
.format( self.time, self.solved, self.total, **self.others) def create_leetcode_readme(self, table_instance): """ create REAdME.md :return: """ file_path = Config.local_path + /README.md # write some basic inform about leetcode with open(file_path, w) as f: f.write(self.msg) f.write(
----------------
) with open(file_path, a) as f: f.write(## LeetCode Solution Table
) f.write(| ID | Title | Difficulty | JavaScript | Python | C++ | Java |
) f.write(|:---: * 7 + |
) table, table_item = table_instance for index in table: item = table_item[index] if item.lock: _lock = :lock: else: _lock = data = { id: item.id_, title: [{}]({}) {}.format(item.title, item.url, _lock), difficulty: item.difficulty, js: item.javascript if item.javascript else To Do, python: item.python if item.python else To Do, c++: item.c_plus_plus if item.c_plus_plus else To Do, java: item.java if item.java else To Do } line = |{id}|{title}|{difficulty}|{js}|{python}|{c++}|{java}|
.format(**data) f.write(line) print(README.md was created.....)

完整代碼請看:(這個可以跑,歡迎使用)

                -------源代碼更好的閱讀體驗,請看這裡,代碼使用方式

#!/usr/bin/env python# Created by Bruce yuan on 18-1-22.import requestsimport osimport jsonimport timeclass Config: """ some config, such as your github page 這裡需要配置你自己的項目地址 1. 本地倉庫的的路徑 2. github中的倉庫leetcode解法的路徑 """ local_path = /home/yuan/PycharmProjects/algorithms_and_oj # solution of leetcode github_leetcode_url = https://github.com/hey-bruce/algorithms_and_oj/blob/master/leetcode-algorithms/ # solution of pat, 暫時還沒寫 github_pat_url = https://github.com/hey-bruce/algorithms_and_oj/blob/master/pat-algorithms/ leetcode_url = https://leetcode.com/problems/class Question: """ this class used to store the inform of every question """ def __init__(self, id_, name, url, lock, difficulty): self.id_ = id_ self.title = name # the problem description url 問題描述頁 self.url = url self.lock = lock # boolean,鎖住了表示需要購買 self.difficulty = difficulty # the solution url self.python = self.java = self.javascript = self.c_plus_plus = def __repr__(self): """ 沒啥用,我為了調試方便寫的 :return: """ return str(self.id_) + + str(self.title) + + str(self.url)class TableInform: def __init__(self): # raw questions inform self.questions = [] # this is table index self.table = [] # this is the element of question self.table_item = {} self.locked = 0 def get_leetcode_problems(self): """ used to get leetcode inform :return: """ # we should look the response data carefully to find law # return byte. content type is byte content = requests.get(https://leetcode.com/api/problems/algorithms/).content # get all problems self.questions = json.loads(content)[stat_status_pairs] # print(self.questions) difficultys = [Easy, Medium, Hard] for i in range(len(self.questions) - 1, -1, -1): question = self.questions[i] name = question[stat][question__title] url = question[stat][question__title_slug] id_ = str(question[stat][frontend_question_id]) if int(id_) < 10: id_ = 00 + id_ elif int(id_) < 100: id_ = 0 + id_ lock = question[paid_only] if lock: self.locked += 1 difficulty = difficultys[question[difficulty][level] - 1] url = Config.leetcode_url + url + /description/ q = Question(id_, name, url, lock, difficulty) self.table.append(q.id_) self.table_item[q.id_] = q return self.table, self.table_item # create problems folders def __create_folder(self, oj_name): oj_algorithms = Config.local_path + / + oj_name + -algorithms if os.path.exists(oj_algorithms): print(oj_name, algorithms is already exits) else: print(creating {} algorithms.....format(oj_name)) os.mkdir(oj_algorithms) for item in self.table_item.values(): question_folder_name = oj_algorithms + / + item.id_ + . + item.title if not os.path.exists(question_folder_name): print(question_folder_name + is not exits, create it now....) os.mkdir(question_folder_name) def update_table(self, oj): # the complete inform should be update complete_info = CompleteInform() self.get_leetcode_problems() # the total problem nums complete_info.total = len(self.table) complete_info.lock = self.locked self.__create_folder(oj) oj_algorithms = Config.local_path + / + oj + -algorithms # 查看os.walk看具體返回的是什麼東西 for _, folders, _ in os.walk(oj_algorithms): for folder in folders: for _, _, files in os.walk(os.path.join(oj_algorithms, folder)): # print(files) if len(files) != 0: complete_info.complete_num += 1 for item in files: if item.endswith(.py): complete_info.solved[python] += 1 folder_url = folder.replace( , "%20") folder_url = os.path.join(folder_url, item) folder_url = os.path.join(Config.github_leetcode_url, folder_url) self.table_item[folder[:3]].python = [Python]({}).format(folder_url) elif item.endswith(.java): complete_info.solved[java] += 1 folder_url = folder.replace( , "%20") folder_url = os.path.join(folder_url, item) folder_url = os.path.join(Config.github_leetcode_url, folder_url) self.table_item[folder[:3]].java = [Java]({}).format(folder_url) elif item.endswith(.cpp): complete_info.solved[c++] += 1 folder_url = folder.replace( , "%20") folder_url = os.path.join(folder_url, item) folder_url = os.path.join(Config.github_leetcode_url, folder_url) self.table_item[folder[:3]].c_plus_plus = [C++]({}).format(folder_url) elif item.endswith(.js): complete_info.solved[javascript] += 1 folder_url = folder.replace( , "%20") folder_url = os.path.join(folder_url, item) folder_url = os.path.join(Config.github_leetcode_url, folder_url) self.table_item[folder[:3]].javascript = [JavaScript]({}).format(folder_url) readme = Readme(complete_info.total, complete_info.complete_num, complete_info.lock, complete_info.solved) readme.create_leetcode_readme([self.table, self.table_item]) print(-------the complete inform-------) print(complete_info.solved)class CompleteInform: """ this is statistic inform """ def __init__(self): self.solved = { python: 0, c++: 0, java: 0, javascript: 0 } self.complete_num = 0 self.lock = 0 self.total = 0 def __repr__(self): return str(self.solved)class Readme: """ generate folder and markdown file update README.md when you finish one problem by some language """ def __init__(self, total, solved, locked, others): """ :param total: total problems nums :param solved: solved problem nums :param others: 暫時還沒用,我想做擴展 """ self.total = total self.solved = solved self.others = others self.locked = locked self.time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) self.msg = # Keep thinking, keep alive
Until {}, I have solved **{}** / **{}** problems while **{}** are still locked.

Completion statistic:
1. JavaScript: {javascript}
2. Python: {python}
3. C++: {c++}
4. Java: {java}

Note: :lock: means you need to buy a book from LeetCode
.format( self.time, self.solved, self.total, self.locked, **self.others) def create_leetcode_readme(self, table_instance): """ create REAdME.md :return: """ file_path = Config.local_path + /README.md # write some basic inform about leetcode with open(file_path, w) as f: f.write(self.msg) f.write(
----------------
) with open(file_path, a) as f: f.write(## LeetCode Solution Table
) f.write(| ID | Title | Difficulty | JavaScript | Python | C++ | Java |
) f.write(|:---: * 7 + |
) table, table_item = table_instance for index in table: item = table_item[index] if item.lock: _lock = :lock: else: _lock = data = { id: item.id_, title: [{}]({}) {}.format(item.title, item.url, _lock), difficulty: item.difficulty, js: item.javascript if item.javascript else To Do, python: item.python if item.python else To Do, c++: item.c_plus_plus if item.c_plus_plus else To Do, java: item.java if item.java else To Do } line = |{id}|{title}|{difficulty}|{js}|{python}|{c++}|{java}|
.format(**data) f.write(line) print(README.md was created.....)def main(): table = TableInform() table.update_table(leetcode)if __name__ == __main__: main()

歡迎使用,歡迎star,Happy Coding!

推薦閱讀:

for循環在Python中是怎麼工作的
回應「如何評價《python web開發實戰》?」的評價
國內有哪些 Django 牛人?
Python從零開始系列連載(12)——Python的基本運算和表達式(下)
為什麼感覺django裡面class based view很難呢?

TAG:Python | Python入门 | Python开发 |