「Python|数据结构」用于数据查询的哈希表:集合和字典

Table of Contents

集合和字典的特点

在抽象的数据结构中, 哈希表是通过一个哈希函数,将给定的数据计算成一个哈希值,这个哈希值对应着哈希表中某个位置,我们可以直接使用这个哈希值访问对应位置上的数据。

python原生数据类型中的集合和字典类型都是哈希表结构。 集合的哈希值会对应元素值,字典的哈希值会对应一个键值对。

集合和字典除了是哈希表结构之后,另外一个特点是:集合元素或字典的键是唯一/ 不重复的

集合的使用场景

由于哈希表的特点,给定的值可以直接计算出一个哈希值来访问集合哈希值的对应位置,所以哈希表结构非常适合进行数据查询

且由于集合没有键值对的概念,只是存储某个值,所以集合适合用于检查数据是否存在/ 数据是否重复。 比如我们要统计今天登录我们网站的用户,那么就可以用集合存储,直接在用户登陆的时候将用户标识放入集合中,由于集合元素的唯一性,所以就算用户一天内登录多次,也只会有一个统计值。

字典的使用场景

字典结构与集合极其相似,只是字典的对应的是一个键值对。换句话说,字典相对于给集合中的每一个元素增加了一个存储空间用于存储额外值。

字典同样是用来存储用于检查的数据。只是我们检查之后会需要使用存储的额外数据。比如,我们要统计用户最近登录时间,那么就可以在用户登录的时候,将用户标识作为字典的键,登录时间作为字典键对应的值。由于字典键跟集合元素一样都唯一的,所以字典中存储的会是每一个用户的最近登录时间。

集合的用法

根据集合适用于数据查询场景,而数据查询的前提是数据存储。所以集合相关的使用主要围绕数据存储和查询,包括:

  • 添加数据(单个数据或多个数据)
  • 检查数据是否存在
  • 删除数据
  • 集合运算,比如:
    • 查询在某个集合中但是不在另一个集合中的数据
    • 同时在两个集合中的数据
    • 两个集合中都不存在的数据
    • 检查某个集合是否是另一个集合的子集

集合相关的使用代码如下:

1# 创建空集合 2empty_set = set() 3 4# 初始化有值集合 5numbers: set = {1, 2, 3, 4} 6set_contained_different_type_elements = {1, "2", "3", 4} 7 8# 将其他可迭代类型的数据结构转换为集合 9values: set = set([1, 2, 3, 4]) 10values: set = set("1234") 11values: set = set(range(1, 5)) 12values: set = set({1: "1", 2: "2", 3: "3"}) # 会得到字段键的集合{1, 2, 3} 13 14# 添加数据(单个) 15empty_set.add(1) 16# 添加多个元素 17empty_set.update([1, "2"]) 18 19# 删除某个元素 20values.discard(1) # 如果1在集合values中, 那么1就会被移除 21values.discard("1") # 如果"1"不在集合values中, 什么都不会发生 22# 如果用另一个删除方法, 不存在元素时会抛出异常 23values.remove(1) # OK 24valus.remove(1900) # 报错 25 26# 删除某个任意元素 27vlaues.pop() # 如果集合为空,会抛出一个错误/异常 28 29# 清空集合 30values.clear() 31 32# 生成集合的副本 33copied_values = values.copy() # 是一个浅拷贝操作 34 35# 集合运算 36set_1 = {1, 2, 3} 37set_2 = {3, 4, 5} 38 39## 合集: 返回一个新集合, 包含两个集合中所有元素 40set_union = set_1.union(set_2) # 由于是合集, 等价于 set_2.union(set_1) 41 42## 差集: 返回一个新集合, 包含在其中一个集合但是不在另一个集合中的元素 43set_1_different_with_set_2 = set_1.difference(set_2) 44set_1_different_with_set_2 = set_1 - set_2 # 等价的快捷写法(即, 语法糖) 45# 等于{1, 2, 3} - {3, 4, 5} = {1, 2} 46 47set_2_different_with_set_1 = set_2.difference(set_1) 48# 等于{3, 4, 5} - {1, 2, 3} = {4, 5} 49 50# 并集: 返回一个新集合, 包含同时在两个集合中的元素 51set_intersection = set_1.intersection(set_2) # 由于是并集, 等价于set_2.intersection(set_1) 52 53# 检查元素是否在集合中: for in 结构 54element = 10 55check_result: bool = element in values 56 57 58# 检查某个集合是否是另一个集合的子集 59check_result: bool = small_set.issubset(big_set)

还有更多内置方法, 可以通过dir(set)查看所有内置方法, 然后用help(set.method_name)查看具体方法的名称。(这个在机考忘记API用法的时候十分好用, 在控制台敲一下就知道正确用法,不算上网查资料作弊)

字典的用法

字典也是涉及到数据存储和数据查询,另外由于字典会存储一个与字典键对应的额外值,这个值可能会在查询后需要取出使用,所以还会涉及到数据访问。

字典的内置方法如下:

内置方法名称功能
clear清空字典的全部内容
copy返回一个新字典,内容是原字典的浅拷贝
get获取某一个键对应的值。可以传入一个默认值作为第二个参数, 在没有要查找的键时返回指定默认值
keys返回字典的所有键
values返回字典中的所有值
items返回字典的所有键值对二元组
pop删除字典中指定的键和值,并将指定键的对应值作为函数返回结果
update更新一个或多个键值对的值
popitem返回最晚放入字典的键值对,返回值跟.()items的元素一样是二元组的形式
setdefault返回指定键的对应值;当键在字典中不存在时,插入指定的默认值后返回默认值作为结果
fromkeys传入一个可迭代类型和一个默认值作为参数用于生成一个新字典,第一个参数的元素作为键,第二个参数作为所有键的值

使用代码如下:

1# 创建一个空字典 2>>> empty = {} 3>>> empty 4{} 5>>> empty = dict() 6>>> empty 7{} 8 9# 字典添加单个键值对 10>>> empty[1] = "1" 11>>> empty 12{1: '1'} 13 14# 字典添加多个键值对 15>>> empty.update({2: "2", 3: "3"}) 16>>> empty 17{1: '1', 2: '2', 3: '3'} 18 19# 获取字典的所有键 20>>> {1: "1", 2: "2", 3: "3"}.keys() 21dict_keys([1, 2, 3]) 22 23# 获取字典的所有值 24>>> {1: "1", 2: "2", 3: "3"}.values() 25dict_values(['1', '2', '3']) 26 27# 获取字典的所有键值对 28>>> {1: "1", 2: "2", 3: "3"}.items() 29dict_items([(1, '1'), (2, '2'), (3, '3')]) 30 31# 从可迭代类型生成一个字典, 第二个参数不传将使得字典的值默认为None 32>>> print(dict.fromkeys([1, 2, 3])) 33{1: None, 2: None, 3: None} 34 35# 从可迭代类型生成一个字典, 所有键的对应值都为第二个参数 36>>> print(dict.fromkeys([1, 2, 3], "123")) 37{1: "123", 2: "123", 3: "123"} 38 39 40# 获取某个存在的值 41>>> {1: "1", 2: "2", 3: "3"}[1] 42'1' 43>>> {1: "1", 2: "2", 3: "3"}.get(1) 44'1' 45 46# 获取某个不存在的值, 会报错方式 47>>> {1: "1", 2: "2", 3: "3"}[4] 48Traceback (most recent call last): 49 File "<stdin>", line 1, in <module> 50KeyError: 4 51 52# 获取某个不存在的值, 不报错方式, 不指定默认值, 默认返回None 53>>> {1: "1", 2: "2", 3: "3"}.get(4) 54 55# 获取某个不存在的值, 不报错方式, 返回指定默认值 56>>> {1: "1", 2: "2", 3: "3"}.get(4, -1) 57-1 58 59>>> values = {1: "1", 2: "2", 3: "3"} 60# 返回指定字典键的对应值 61>>> values.pop(1) 62'1' 63>>> values 64{2: '2', 3: '3'} 65 66# 返回最晚放入字典的键值对 67>>> values.popitem() 68(3, '3') 69>>> values 70{2: '2'} 71 72# 查询元素是否在字典的键中 73check_result: bool = target_key in dict_to_check 74 75

由于字典键的值可能确实是None, 所以不能用以下的get方法检查: ❌ check_result: bool = dict_to_check.get(target_key) is None

你所需要记住的

总结一下,需要记住的是以下几点:

  • 需要数据查询的时候使用集合和字典
  • 如果需要存储额外值供后续使用,则使用字典
  • 使用dir(set)dir(set.method_name)来查看集合和字典的内置方法以及具体的功能和使用方式

好书推荐:

好课推荐:

写文不易,如果对你有帮助的话,来一波点赞、收藏、关注吧~👇

Mastodon