1. 场景描述
吉米是太平洋岛国一个贫苦家庭的孩子,他的梦想就是当总统,引领国家走向富强之路。
开学的第一堂课上,老师用白色的粉笔在黑板上写下了“我的梦想”,同学们都陷入了思考。大卫的梦想是当一名科学家,用奇思妙想改变世界,探索人类未知的秘密;杰克的梦想是当一名妙手回春的医生,用高超的医术解除病人的痛苦;迪娜的梦想是当一名歌手,让自己的歌声传遍世界的每一个角落;吉米的梦想是当总统,刚说到这里,教室里就传来一阵又一阵的嘲笑声,因为吉米的父亲是一个农民,吉米家连温饱都无法保障,他想当总统,简直就是痴人说梦。在走出校园的那一年,吉米接替了父亲当上了农民。吉米能够吃苦耐劳,在地里一呆就是30多年,他研发出了很多能让农作物产量成倍提升的方法,55岁的吉米拥有了自己的绿色生态农业公司。吉米的公司座落在城市最繁华的地段,生意越做越大,吉米成了全国知名的企业家,与此同时他还热心公益,回报社会。吉米70岁那年,他的绿色生态农业公司成功上市了。望着窗外的摩天大厦,口中反复念叨着他儿时的梦想,在那个物质极度匮乏的年代许下的愿望,半个多世纪过去了都一直未曾改变。73岁的吉米决定参加总统选举,最终因为身体原因不得不中途退出竞选。在他弥留之际,他告诉儿子小吉米:我从小的梦想就是当总统,引领国家走向富强之路。现在我倒在了追求梦想的路上,此生无悔!十年之后,小吉米也参加了总统竞选,最后吉米以压倒性优势战胜其他竞选人,成功当选新一届总统。
吉米父子的故事给我们的启迪:在实现梦想的道路上都会遭遇无尽的荆棘,只要坚持梦想,在追梦的路上不断前行,终能创造奇迹,梦想成真。
下面我们将根据以上场景,模拟总统大选的投票和选票统计的过程。
2. 编程思路
为了模拟投票和计票过程,我们需要解决以下几个关键问题:
2.1 参选人
使用字典candidates存放参选人信息,字典的键是参选人编号,字典的值是参选人姓名。内容如下:
candidates = {1: ‘jimmy’, 2: ‘jenifer’, 3: ‘peter’, 4: ‘linda’, 5: ‘roger’}
这个字典描述了5位参选人。1号参选人是jimmy,2号参选人是jenifer,3号参选人是peter,以此类推。
2.2 选票
我们使用列表votes来存放选票,这个列表中的每个元素代表一张选票,它是一个整数,对应参选人字典candidates中的参选人编号。例如:
votes = [1,5,3,1,1]
表示列表votes中存放了5张选票,对照字典candidates找出映射关系,我们可以得出结论:
jimmy : 3 张选票
roger : 1 张选票
peter : 1 张选票
2.3 模拟生成选票
编写函数make_votes(voter_num, candidate_num),模拟生成选票。其中参数voter_num代表投票人数,candidate_num代表参选人数;返回值是一个存放选票的列表votes。其内容为如下样式:
votes = [1, 3, 5, 2, 1, 4, 4, 1]
2.4 统计选票
编写函数count_votes(votes),实现选票统计功能。参数votes是一个列表,存放所有参选人的选票。返回值是字典candidate_votes,诸如以下内容:
candidate_votes = { 1:3, 3:1, 5:1, 2:1, 4:2 }
代表如下含义:
jimmy : 3 张选票;
peter : 1 张选票;
roger : 1 张选票;
jenifer : 1 张选票;
linda : 2 张选票。
2.5 统计结果可视化
编写函数:visualize(index, value, color),绘制选票统计直方图。其输入参数index为参选人姓名列表,value 是选票数列表,而color则是绘图中使用的颜色列表。
3. 代码实现
"""
elect.py : 吉米的总统梦想
"""
import random
from sys import argv, exit
from matplotlib import pyplot as plt
candidates = {1: 'jimmy', 2: 'jenifer', 3: 'peter', 4: 'linda', 5: 'roger'} # 参选人字典
color_lst = ['aquamarine', 'dodgerblue', 'indianred', 'darkorange', 'seagreen'] # 颜色列表
def make_votes(voter_num, candidate_num):
"""
功能:模拟生成选票
参数:
voter_num : 投票人数
candidate_num : 参选人数
返回:
votes :选票列表
"""
votes = []
for i in range(voter_num): # ①
vote = random.randint(1, candidate_num) # ②
votes.append(vote) # ③
return votes
def count_votes(votes):
"""
功能:按参选人统计选票
参数:
votes :选票池列表
返回:
candidate_votes : 包含参选人编号及选票数的字典
"""
candidate_votes = {}
for vote in votes: # ④
if vote in candidate_votes: # ⑤
candidate_votes[vote] += 1
else:
candidate_votes[vote] = 1
return candidate_votes
def visualize(index, value, color):
"""
功能:选票数据可视化,绘制直方图
参数:
index : 参选人列表
value : 参选人所得选票数的列表
color : 绘图使用的颜色列表
"""
fig_mgr = plt.get_current_fig_manager()
fig_mgr.set_window_title("Counting-Votes")
plt.xlabel('Candidates', color='red')
plt.ylabel('Votes', color='red')
plt.bar(index, value, width=0.7, color=color)
plt.title('Counting - Votes', color='red')
data = zip(index, value) # ⑥
for x, y in data: # ⑦
plt.text(x, y, y, ha='center', va='bottom')
plt.show()
def main():
if len(argv) != 2:
print('Usage: elect.py voter_number')
exit(1)
voters = int(argv[1])
votes = make_votes(voters, len(candidates)) # ⑧
candidate_votes = count_votes(votes) # ⑨
index = [candidates[k] for k in candidate_votes]
value = candidate_votes.values()
visualize(index, value, color_lst) # ⑩
if __name__ == '__main__':
main()
程序主要语句说明如下:
语句①按照投票人数,生成选票。每个投票人只能投一票,并且只能投给1名参选人;
语句②随机生成1张选票,使用一个整数表示,其含义是参选人编号;
语句③将1张选票添加到选票列表votes中,我们可以把votes理解为选票池;
语句④通过循环语句,对选票池中的每一张进行分类统计;
语句⑤按参选人编号分类,统计累加所得选票数;
语句⑥生成可迭代变量data,其中每个元素是包含参选人姓名和得票数的元组,诸如以下内容:
[ (‘jimmy’, 26), (‘roger’, 20), (‘jenifer’, 18), (‘peter’, 13), (‘linda’, 23) ]
语句⑦完成在直方图的立柱打印选票数;
语句⑧调用make_votes()创建选票池,参数分别是投票人数和参选人数;
语句⑨调用count_votes()统计选票,输入参数是选票池votes列表;
语句⑩调用函数visualize()实现选票可视化展现,它是通过调用第三方绘图库matplotlib实现的。
4. 运行效果
4.1 运行环境
由于数据可视化部分使用了第三方绘图库:matplotlib,所以在程序运行之前,我们需要在Python环境中进行手动安装,可在Windows命令行窗口中执行以下命令即可:
D:>pip install matplotlib
如果安装速度慢,可以指定安装源。执行以下命令,将完成快速安装:
D:>pip install matplotlib -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
4.2 程序执行
D:\cases\吉米的总统梦想>python elect.py 100
代表有100人参加选举投票,程序执行结果如下图所示:
在以上图表中:横轴代表候选人,纵轴代表候选人所获得的选票数。
如果你对本案例的免费视频讲解有兴趣,可在百度中搜索:寰银学堂,观看项目开发实践 -“选票统计可视化”。
4.3 压力测试
如果需要统计百万、千万、甚至是上亿量级的选票,执行本程序会导致电脑系统宕机崩溃吗?需要什么样配置的电脑可以完成此项任务?笔记本电脑是否可以胜任呢?
我们强烈鼓励读者进行以上压力测试,或许这样的测试将会颠覆一些传统固有的思维定式,增长全新的见识。
4.4 优化建议
到目前为此,elect.py程序模块的代码量超过60多行,为方便日后的代码维护和代码重用,我们可以把函数make_votes(), count_votes()和函数visualize()的程序代码从模块elect.py中剥离出来,形成新的子模块可取名为votes.py,并在主模块elect.py中使用语句from votes import *,这样你就可以使用子模块中的函数了。关于具体的实现方法在此不再赘述。