Python实例:字典共同键值查找的两种实现方法
一、实际场景
比如,NBA每场球星的得分统计,都以字典格式存储:
第一场:{'詹姆斯': 32, '库里': 22, '字母哥': 18, ...}
第二场:{'詹姆斯': 23, '恩比德': 17, '杜兰特': 28, ...}
第三场:{'詹姆斯': 27, '哈登': 19, '利拉德': 16, ...}
…
下面我们需要统计出前N场比赛,每场进球都在20分以上的球员。
其实,上面的场景就是在N个字典中寻找公共键值的问题,这里给出两种解决方案。
二、字典共同键值查找的实现方法
2.1 直观的解决方法
为了解决这个问题,我们首先假设只有3场比赛,则解决上面问题的步骤为:
- 1、使用
randint
方法简便的设计3场比赛和每个球员每场比赛进球的字典数据; - 2、使用
filter
函数对每场比赛进行球员得分筛选,剔除每场比赛小于20分的球员; - 3、对于比赛场数比较少的时候,可以考虑直接使用列表解析方法,得到在这三场比赛中,得分都在20分以上的球员。
from random import randint
# 球员列表:
player_list = ['詹姆斯', '库里', '字母哥', '恩比德', '杜兰特',
'哈登', '利拉德', '戴维斯', '乔治']
# 1.构造3场比赛每个球员的进球数
round_1 = {player: randint(0, 32) for player in player_list}
round_2 = {player: randint(0, 32) for player in player_list}
round_3 = {player: randint(0, 32) for player in player_list}
# 2.筛选3场比赛球员进球字典中进球数大与20的球员
round_1_filter = dict(filter(lambda x: x[1] >= 20, round_1.items()))
round_2_filter = dict(filter(lambda x: x[1] >= 20, round_2.items()))
round_3_filter = dict(filter(lambda x: x[1] >= 20, round_3.items()))
# 3.使用列表解析分析在这三场比赛中,得分都在20分以上的球员:
player_with_20score = [player for player in round_1_filter
if (player in round_2_filter) and (player in round_3_filter)]
# 4.输出三场比赛得分均在20分以上的球员
print('三场比赛得分均在20分以上的球员:', player_with_20score)
上述解决方法对于比赛场数表少时还可以考虑使用。假如,要统计一个赛季每场比赛都在15分以上的球员呢?我们总不能手动的一个个输入吧;或者我们在得到数据之前并不知道要统计多少个场次的比赛。所以,下面设计一个更加通用的解决方法。
2.2 更为通用的解决方法
更为通用的解决方案步骤如下所示:
- 1、首先通过字典解析的嵌套应用,构造一个嵌套字典格式的随机场次为N的比赛,且以字典形式存储对应场次的比赛中每个球员的得分情况的字典
round_dict
,字典数据格式如下所示:
- 2、对
round_dict
字典进行键值和值的遍历,并使用filter
函数结合匿名函数lambda
对round_dict
字典中得分在15分以上的球员进行筛选,得到只包含每场比赛得分在15分以上的数据字典round_dict_filter
。round_dict_filter
字典中的数据内容如下图所示:
- 3、由于字典不支持通过
[x]
角标读取数据,所以先将筛选后的字典round_dict_filter
中的值(不用转换键值)转换为只包含球员得分数据的字典列表round_value_list
,其数据格式如下所示:
为了找出round_dict_filter
中每场比赛得分均在15分以上的球员,可以使用如下的列表解析方法,并配合匿名函数lambda
和map
函数实现:
players_15_score = [player for player in round_value_list[0]
if all(map(lambda x: player in x, round_value_list[1:]))]
上面代码中的player for player in round_value_list[0]
指令首先将第一场比赛的球员的键值变为可迭代对象player
,然后使用lambda
匿名函数将除了第一场比赛外的其余场次中的球员变为可迭代对象,并通过指令all(map(lambda x: player in x, round_value_list[1:]))
判断第一场的球员是否在剩余所有的场次中。
from random import randint
# 球员列表:
player_list = ['詹姆斯', '库里', '字母哥', '恩比德', '杜兰特',
'哈登', '利拉德', '戴维斯', '乔治', '米切尔', '英格拉姆',
'拉文', '唐斯', '巴特勒']
# 1.使用字典嵌套解析生成字典数据数据:
# 下面的代码生成一个5-15随机比赛场数,
# 每场每个球员得分在8-40之间的字典数据
round_dict = {'round_%d' % i: {player: randint(8, 40)
for player in player_list}
for i in range(randint(5, 15))}
# 2.下面的代码是直接针对字典进行数据筛选操作的,操作的结果为:
# (1) 开辟一个新的字典空间用于存储筛选后的数据:
round_dict_filter = {}
# (2) 将每场比赛中球员得分在15分以上的数据留下,
# 并存储于round_dict_filter字典。
for key, value in round_dict.items():
round_dict_filter[key] = dict(filter(
lambda x: x[1] >= 15, value.items()))
# 3.使用列表解析分析在N场比赛中,得分都在15分以上的球员:
# (1) 首先将以字典格式存储的每场比赛每个球员的得分转换为
# 列表形式
round_value_list = list(round_dict_filter.values())
# (2) 筛选每场都在15分以上的球员
players_15_score = [player for player in round_value_list[0]
if all(map(lambda x: player in x, round_value_list[1:]))]
# 4.输出三场比赛得分均在15分以上的球员
print('三场比赛得分均在15分以上的球员:', players_15_score)