需求:1.不放回抽簽 2.把名單上的人員都抽取完以后才能開始下一輪 3.每次打分數都累加 4.可以查看前三和后三名
使用excel實現:思路就是先拿到名單數據,然后抽簽(判斷抽出來的人在不在新list中),打分,排序。使用遞歸調用實現多次抽取。
數據樣例:
import xlrd import random import sys from openpyxl import load_workbook filename = '參訓人員名單.xlsx' name_new_list = [] def open_excel(): xl = xlrd.open_workbook(filename) sheet = xl.sheet_by_index(0) return sheet def read_name(): sheet = open_excel() row_num = sheet.nrows# 獲取excel中有多少行 name_score = [] for i in range(1,row_num): value = sheet.row_values(i)#取出每一行的名字和分數 name_score.append(value) new_name_score = dict(name_score) #返回姓名分數列表 return new_name_score def draw_people(): names = read_name() # 獲取姓名分數字典 name_list = list(names.keys()) # 把姓名拿出來,當一個列表,用來抽取 if len(name_new_list) == len(name_list):# 如果原始列表和存放抽取名字的列表相等,清空存放名字列表 nu = input('名單上的人員都已被抽過!開啟新一輪的抽簽請輸入1\n 返回上級菜單請輸入2\n') if nu == '1': name_new_list.clear() else: return #返回主菜單 people_name = random.choice(name_list) if people_name not in name_new_list: name_new_list.append(people_name) name_num = name_list.index(people_name)+2 # 獲取序號+2,因為下標從0開始, print('此次抽中的人員是:',people_name) mark_score(name_num) else: draw_people() def mark_score(people_num): wb = load_workbook(filename) wb1 = wb.active # 激活sheet old_score = wb1.cell(row = people_num,column = 2).value #取出原始分數 print("該人員的現有分數是:",old_score) while True: try: this_score = input("請給抽中的人員打分數(請輸入整數):") this_score = int(this_score) break except ValueError: print('請輸入一個整數') now_score = int(old_score) + int(this_score) wb1.cell(people_num,2,now_score)#寫入分數列 wb.save(filename) # 保存 def sort_score(): #排序 all_score = read_name()#拿到姓名和分數組成的字典 for key in all_score: all_score[key] = int(all_score[key]) # 把數字的小數點去掉才排序 desc = sorted(all_score.items(),key=lambda x:x[1], reverse=False)[:3]#倒序排,輸出前三 asc = sorted(all_score.items(),key=lambda x:x[1], reverse=True)[:3]#正序排,輸出前三 print("排名前三的人員:",asc) print("排名后三的人員:",desc) def main(): num = input("---抽簽,請輸入1\n---查看排名,請輸入2\n---退出程序,請輸入3\n") if num == '1' : draw_people() main() elif num == '2': sort_score() main() else: sys.exit(0) if __name__ == '__main__': main()
用txt實現:先讀出全部數據,然后分割成列表。寫入的時候現封裝成一個列表,再寫進去。排序時應該先把value轉成int,才能進行排序
數據樣例:
import random import sys import codecs import operator filename = '名單.txt' name_new_list = [] name_dict = {} def read_txt(): with codecs.open(filename, 'r', 'utf-8') as fp: data = fp.readlines() ''' 讀取到的data: ['張三:62\r\n', '李四:117\r\n', 'waang2:40\r\n', 'yuuu:60\r\n', '李磊:90'] ''' for line in data: name_score = line.replace('\r', '').replace('\n', '').split(':') # 把每一行數據用:拆分成2個元素 ''' ['張三', '62'] ['李四', '117'] ['waang2', '40'] ['yuuu', '60'] ['李磊:90'] ''' if len(name_score) == 2: # 以防txt里面有空行 name_dict[name_score[0]] = int(name_score[1]) #把value轉成int,用於后面的加減和排序 return name_dict def draw_people(name_list): if len(name_new_list) == len(name_list): # 如果原始列表和存放抽取名字的列表相等,清空存放名字列表 nu = input('名單上的人員都已被抽過!開啟新一輪的抽簽請輸入1 返回上級菜單請輸入2\n') if nu == '1': name_new_list.clear() else: return while True: people_name = random.choice(name_list) if people_name not in name_new_list: name_new_list.append(people_name) print('此次抽中的人員是:', people_name) mark_score(people_name, name_dict) break ''' 使用遞歸調用 people_name = random.choice(name_list) if people_name not in name_new_list: name_new_list.append(people_name) print('此次抽中的人員是:', people_name) mark_score(people_name, name_dict) else: draw_people() ''' def mark_score(people_name, name_dict): print("該人員的現有分數是:%s分" % (name_dict[people_name])) while True: try: now_score = int(input("請給抽中的人員打分數(請輸入整數):")) name_dict[people_name] += now_score # 總分 with open(filename, 'w', encoding='utf-8') as f: tmp = '' for key in name_dict: # 用key來循環,把key和value組裝 tmp += (str(key) + ":" + str(name_dict[key]) + '\n') f.writelines(tmp) # 一次性寫入 f.close() # 保存 break except ValueError: print('請輸入一個整數') def sort_score(name_and_score): # 排序 desc = sorted( name_and_score.items(), key=operator.itemgetter(1), reverse=False)[:3] # 倒序排,輸出前三 asc = sorted( name_and_score.items(), key=operator.itemgetter(1), reverse=True)[:3] # 正序排,輸出前三 ''' name_and_score.items(): dict_items([('張三', 506), ('李四', '344'), ('waang2', '4029'), ('yuuu', '64')]) operator排序速度比匿名函數更快,也支持多個關鍵字同時排序。,operator.itemgetter函數獲取的不是值,而是定義了一個函數,通過該函數作用到對象上才能獲取值。 itemgetter(1)是獲取items()對象的第一個域,對域的值排序(對value排序) ''' print("排名前三位的人員:", dict(asc)) print("排名后三位的人員:", dict(desc)) def main(): name_score = read_txt() name_list = list(name_score.keys()) # 把姓名拿出來,當一個列表,用來抽取 num = input("---抽簽,請輸入1\n---查看排名,請輸入2\n---退出程序,請輸入3\n請輸入:") if num == '1': draw_people(name_list) print('\r') main() elif num == '2': sort_score(name_score) print('\r') main() else: sys.exit(0) if __name__ == '__main__': main()
抽簽方法不用遞歸,用while循環實現
def draw_people(): name_score = read_txt() name_list = list(name_score.keys()) # 把姓名拿出來,當一個列表,用來抽取 if len(name_new_list) == len(name_list):# 如果原始列表和存放抽取名字的列表相等,清空存放名字列表 nu = input('名單上的人員都已被抽過!開啟新一輪的抽簽請輸入1 返回上級菜單請輸入2\n') if nu == '1': name_new_list.clear() else: return while True: people_name = random.choice(name_list) if people_name not in name_new_list: name_new_list.append(people_name) print('此次抽中的人員是:',people_name) mark_score(people_name,name_dict) break