第十二讲 常用数据结构之集合

news2024/9/20 20:31:52

在学习了列表和元组之后,我们再来学习一种容器型的数据类型,它的名字叫集合(set)。说到集合这个词大家一定不会陌生,在数学课本上就有这个概念。如果我们把一定范围的、确定的、可以区别的事物当作一个整体来看待,那么这个整体就是集合,集合中的各个事物称为集合的元素。通常,集合需要满足以下特性:

  1. 无序性:一个集合中,每个元素的地位都是相同的,元素之间是无序的。
  2. 互异性:一个集合中,任何两个元素都是不相同的,即元素在集合中只能出现一次。
  3. 确定性:给定一个集合和一个任意元素,该元素要么属这个集合,要么不属于这个集合,二者必居其一,不允许有模棱两可的情况出现。

Python 程序中的集合跟数学上的集合没有什么本质区别,需要强调的是上面所说的无序性和互异性。无序性说明集合中的元素并不像列中的元素那样存在某种次序,可以通过索引运算就能访问任意元素,集合并不支持索引运算。另外,集合的互异性决定了集合中不能有重复元素,这一点也是集合区别于列表的地方,我们无法将重复的元素添加到一个集合中。集合类型必然是支持innot in成员运算的,这样就可以确定一个元素是否属于集合,也就是上面所说的集合的确定性。集合的成员运算在性能上要优于列表的成员运算,这是集合的底层存储特性决定的,此处我们暂时不做讨论,大家记住这个结论即可。

说明:集合底层使用了哈希存储(散列存储),对哈希存储感兴趣的读者可以看看维基百科上“散列表”这个词条。

创建集合

在 Python 中,创建集合可以使用{}字面量语法,{}中需要至少有一个元素,因为没有元素的{}并不是空集合而是一个空字典,字典类型我们会在下一节课中为大家介绍。当然,也可以使用 Python 内置函数set来创建一个集合,准确的说set并不是一个函数,而是创建集合对象的构造器,这个知识点会在后面讲解面向对象编程的地方为大家介绍。我们可以使用set函数创建一个空集合,也可以用它将其他序列转换成集合,例如:set('hello')会得到一个包含了4个字符的集合(重复的字符l只会在集合中出现一次)。除了这两种方式,还可以使用生成式语法来创建集合,就像我们之前用生成式语法创建列表那样。

set1 = {1, 2, 3, 3, 3, 2}
print(set1)  # {1, 2, 3}

set2 = {True, False, True, True, False}
print(set2)  # {False, True}

set3 = set('hello')
print(set3)  # {'l', 'o', 'e', 'h'}

set4 = set([1, 2, 2, 3, 3, 3, 2, 1])
print(set4)  # {1, 2, 3}

set5 = {num for num in range(1, 20) if num % 3 == 0 or num % 7 == 0}
print(set5)  # {3, 6, 7, 9, 12, 14, 15, 18}

set6 = {('骆昊', 43), ('王大锤', 18)}
print(set6)  # {('王大锤', 18), ('骆昊', 43)}
复制代码

需要提醒大家,集合中的元素必须是hashable类型,使用哈希存储的容器都会对元素提出这一要求。所谓hashable类型指的是能够计算出哈希码的数据类型,通常不可变类型都是hashable类型,如整数(int)、浮点小数(float)、布尔值(bool)、字符串(str)、元组(tuple)等。可变类型都不是hashable类型,因为可变类型无法计算出确定的哈希码,所以它们不能放到集合中。例如:我们不能将列表作为集合中的元素;同理,由于集合本身也是可变类型,所以集合也不能作为集合中的元素。我们可以创建出嵌套的列表,但是我们不能创建出嵌套的集合,这一点在使用集合的时候一定要引起注意。

集合的遍历

我们可以通过len函数来获得集合中有多少个元素,但是我们不能通过索引运算来遍历集合中的元素,因为集合元素并没有特定的顺序。当然,要实现对集合元素的遍历,我们仍然可以使用for-in循环,代码如下所示。

set1 = {'Python', 'C++', 'Java', 'Kotlin', 'Swift'}
for elem in set1:
    print(elem)
复制代码

提示:大家看看上面代码的运行结果,通过单词输出的顺序体会一下集合的无序性。

集合的运算

Python 为集合类型提供了非常丰富的运算符,主要包括:成员运算、交集运算、并集运算、差集运算、比较运算(相等性、子集、超集)等。

成员运算

可以通过成员运算innot in 检查元素是否在集合中,代码如下所示。

set1 = {11, 12, 13, 14, 15}
print(10 in set1)      # False 
print(15 in set1)      # True
set2 = {'Python', 'Java', 'C++', 'Swift'}
print('Ruby' in set2)  # False
print('Java' in set2)  # True
复制代码

二元运算

集合的二元运算主要指集合的交集、并集、差集、对称差等运算,这些运算可以通过运算符来实现,也可以通过集合类型的方法来实现,代码如下所示。

set1 = {1, 2, 3, 4, 5, 6, 7}
set2 = {2, 4, 6, 8, 10}

# 交集
print(set1 & set2)                      # {2, 4, 6}
print(set1.intersection(set2))          # {2, 4, 6}

# 并集
print(set1 | set2)                      # {1, 2, 3, 4, 5, 6, 7, 8, 10}
print(set1.union(set2))                 # {1, 2, 3, 4, 5, 6, 7, 8, 10}

# 差集
print(set1 - set2)                      # {1, 3, 5, 7}
print(set1.difference(set2))            # {1, 3, 5, 7}

# 对称差
print(set1 ^ set2)                      # {1, 3, 5, 7, 8, 10}
print(set1.symmetric_difference(set2))  # {1, 3, 5, 7, 8, 10}
复制代码

通过上面的代码可以看出,对两个集合求交集,&运算符和intersection方法的作用是完全相同的,使用运算符的方式显然更直观且代码也更简短。需要说明的是,集合的二元运算还可以跟赋值运算一起构成复合赋值运算,例如:set1 |= set2相当于set1 = set1 | set2,跟|=作用相同的方法是updateset1 &= set2相当于set1 = set1 & set2,跟&=作用相同的方法是intersection_update,代码如下所示。

set1 = {1, 3, 5, 7}
set2 = {2, 4, 6}
set1 |= set2
# set1.update(set2)
print(set1)  # {1, 2, 3, 4, 5, 6, 7}
set3 = {3, 6, 9}
set1 &= set3
# set1.intersection_update(set3)
print(set1)  # {3, 6}
set2 -= set1
# set2.difference_update(set1)
print(set2)  # {2, 4}
复制代码

比较运算

两个集合可以用==!=进行相等性判断,如果两个集合中的元素完全相同,那么==比较的结果就是True,否则就是False。如果集合A的任意一个元素都是集合B的元素,那么集合A称为集合B的子集,即对于∀a∈A∀a∈A,均有a∈Ba∈B,则A⊆BA⊆B,AB的子集,反过来也可以称BA的超集。如果AB的子集且A不等于B,那么A就是B的真子集。Python 为集合类型提供了判断子集和超集的运算符,其实就是我们非常熟悉的<<=>>=这些运算符。当然,我们也可以通过集合类型的方法issubsetissuperset来判断集合之间的关系,代码如下所示。

set1 = {1, 3, 5}
set2 = {1, 2, 3, 4, 5}
set3 = {5, 4, 3, 2, 1}

print(set1 < set2)   # True
print(set1 <= set2)  # True
print(set2 < set3)   # False
print(set2 <= set3)  # True
print(set2 > set1)   # True
print(set2 == set3)  # True

print(set1.issubset(set2))    # True
print(set2.issuperset(set1))  # True
复制代码

说明:上面的代码中,set1 < set2判断set1是不是set2的真子集,set1 <= set2判断set1是不是set2的子集,set2 > set1判断set2是不是set1的超集。当然,我们也可以通过set1.issubset(set2)判断set1是不是set2的子集;通过set2.issuperset(set1)判断set2是不是set1的超集。

集合的方法

刚才我们说过,Python 中的集合是可变类型,我们可以通过集合类型的方法向集合添加元素或从集合中删除元素。

set1 = {1, 10, 100}

# 添加元素
set1.add(1000)
set1.add(10000)
print(set1)  # {1, 100, 1000, 10, 10000}

# 删除元素
set1.discard(10)
if 100 in set1:
    set1.remove(100)
print(set1)  # {1, 1000, 10000}

# 清空元素
set1.clear()
print(set1)  # set()
复制代码

说明:删除集合元素的remove方法在元素不存在时会引发KeyError错误,所以上面的代码中我们先通过成员运算判断元素是否在集合中。集合类型还有一个pop方法可以从集合中随机删除一个元素,该方法在删除元素的同时会获得被删除的元素,而removediscard方法仅仅是删除元素,不会获得被删除的元素。

集合类型还有一个名为isdisjoint的方法可以判断两个集合有没有相同的元素,如果没有相同元素,该方法返回True,否则该方法返回False,代码如下所示。

set1 = {'Java', 'Python', 'C++', 'Kotlin'}
set2 = {'Kotlin', 'Swift', 'Java', 'Dart'}
set3 = {'HTML', 'CSS', 'JavaScript'}
print(set1.isdisjoint(set2))  # False
print(set1.isdisjoint(set3))  # True
复制代码

不可变集合

Python 中还有一种不可变类型的集合,名字叫frozensetsetfrozenset的区别就如同listtuple的区别,frozenset由于是不可变类型,能够计算出哈希码,因此它可以作为set中的元素。除了不能添加和删除元素,frozenset在其他方面跟set是一样的,下面的代码简单的展示了frozenset的用法。

fset1 = frozenset({1, 3, 5, 7})
fset2 = frozenset(range(1, 6))
print(fset1)          # frozenset({1, 3, 5, 7})
print(fset2)          # frozenset({1, 2, 3, 4, 5})
print(fset1 & fset2)  # frozenset({1, 3, 5})
print(fset1 | fset2)  # frozenset({1, 2, 3, 4, 5, 7})
print(fset1 - fset2)  # frozenset({7})
print(fset1 < fset2)  # False
复制代码

总结

Python 中的集合类型是一种无序容器不允许有重复运算,由于底层使用了哈希存储,集合中的元素必须是hashable类型。集合与列表最大的区别在于集合中的元素没有顺序、所以不能够通过索引运算访问元素、但是集合可以执行交集、并集、差集等二元运算,也可以通过关系运算符检查两个集合是否存在超集、子集等关系。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/467730.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

三维可视化智慧档案馆之八防环境监控系统平台白皮书

目录 一、智慧档案馆建设目的 二、智慧档案馆集成度 三、智慧档案馆架构 3.1库房环境监测 3.2库房安防监控 四、智慧档案馆功能简介 4.1档案室一体化控制管理系统建设方案 4.2温湿度检测建设方案 4.3恒温控制建设方案 4.4烟雾感应检测系统 4.5安防系统建设…

STM32开发(十七)STM32F103 片内资源 —— 独立看门狗 IWDG 详解

文章目录 一、基础知识点二、开发环境三、STM32CubeMX相关配置四、Vscode代码讲解五、结果演示 一、基础知识点 STM32F10xxx内置两个看门狗&#xff0c;提供了更高的安全性、时间的精确性和使用的灵活性。两个看门狗设备(独立看门狗和窗口看门狗)可用来检测和解决由软件错误引…

数据库做实验过程-------pyqt环境的配置

首先下载anacunda Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 找到windows最新版x86 64版本等待下载 双击运行安装包 此时一定要记录文件夹的位置&#xff0c;便于以后环境变量的配置。 别看是4.7但是以后可能会增加新的配置&…

学生管理系统

一、项目框架 二、 CommandInfo.cs: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data.Common; //using MySql.Data.MySqlClient;namespace WinStudent {public class CommandInf…

JMU Oracle 实验五

问的问题 看了一下log和logfile&#xff0c;就是重做日志组和日志文件的地址信息看了归档的地址如何执行归档&#xff0c;就是switch那个语句 1. 查询Oracle数据库当前使用的联机重做日志文件组及成员信息 v$log&#xff1a;记录有关重做日志文件组相关的信息。 v$logfile&a…

数据结构——栈的构建

在本次的博客当中我们来向大家介绍两个看似很新没有听过&#xff0c;实际上我们之前已经实现过了的数据结构——栈和队列。 &#x1f335;栈 实质上栈就是一个具有特殊要求的线性表。栈在定义上要求我们只能从一端插入和一段删除数据。举一个简单的例子&#xff1a;我们一次向栈…

MySQL的ID用完了,怎么办?

目 录 一 首先首先分情况 二 自增ID 1 mysql 数据库创建一个自增键的表 2 导出表结构 3 重新创建 自增键是4294967295的表 4 查看表结构 5 异常测试 三 填充主键 1 首先创建一个test 表&#xff0c;主键不自增 2 插入主键最大值 3 再次插入主键最大值1 四 没有声明…

SSO、CAS、OAuth、OIDC

参考 简单了解概念&#xff1a; https://www.bilibili.com/video/BV1XG411w7DN/简单了解操作&#xff1a; https://www.bilibili.com/video/BV1334y11739/ openid-connect&#x1f44d;流程图解&#xff1a; https://www.youtube.com/watch?vt18YB3xDfXI &#xff08;图&#…

conda虚拟环境配置

文章目录 1 下载Anaconda2 创建自己的虚拟环境3 配置自己的虚拟环境 1 下载Anaconda 直接官网下载 Anaconda官网 2 创建自己的虚拟环境 可以直接在anaconda软件上添加 还可以通过命令行指令&#xff0c;打开终端输入conda create -n 名字 python3.7 3 配置自己的虚拟环境…

大厂高频面试:底层的源码逻辑知多少?

你好&#xff0c;我是何辉。今天我们来聊一聊Dubbo的大厂高频面试题。 大厂面试&#xff0c;一般重点考察对技术理解的深度&#xff0c;和中小厂的区别在于&#xff0c;不仅要你精于实战&#xff0c;还要你深懂原理&#xff0c;勤于思考并针对功能进行合理的设计。 网上一直流…

一文读懂RabbitMQ消息队列

一.什么是消息队列 1.简介 在介绍消息队列之前&#xff0c;应该先了解什么是 AMQP&#xff08;Advanced Message Queuing Protocol, 高级消息队列协议,点击查看&#xff09; 消息&#xff08;Message&#xff09;是指在应用间 传送的数据&#xff0c;消息可以非常简单&#xff…

【Golang开发入门】你真的会用Go写“Hello world“吗?

博主简介&#xff1a;努力学习的大一在校计算机专业学生&#xff0c;热爱学习和创作。目前在学习和分享&#xff1a;数据结构、Go&#xff0c;Java等相关知识。博主主页&#xff1a; 是瑶瑶子啦所属专栏: Go语言核心编程近期目标&#xff1a;写好专栏的每一篇文章 目录 一、Go项…

Zynq-7000、FMQL45T900的GPIO控制(六)---linux驱动层配置GPIO输入输出控制

本文使用的驱动代码 Zynq-7000、FMQL45T900的GPIO控制&#xff08;六&#xff09;-linux驱动层配置GPIO输入输出控制资源-CSDN文库 在Zynq-7000、FMQL45T900驱动层也时常会用到对GPIO的控制&#xff0c;这里就针对实际使用的情况进行说明&#xff0c;首先根据之前的帖子确实使…

监测HDD smart信息的脚本编写

最近需要完成一个测试HDD的项目&#xff0c;因为接的HDD太多&#xff0c;手动查看smart信息太麻烦&#xff0c;所以需要写一个自动帮我们检查smart信息的脚本。此遍文章只介绍直连或者JBOD模式下的信息监测&#xff0c;没有涉及到组RAID模式。 1 首先看下HDD的smart信息&#x…

谁在成为产业经济发展的推车人?

区域发展的新蓝图中&#xff0c;京东云能做什么&#xff1f;它的角色是什么&#xff1f;这个问题背后&#xff0c;隐藏的不仅是京东云自身的能力和价值&#xff0c;更是其作为中国互联网云厂商的代表之一&#xff0c;对“技术产业”的新论证。 作者|皮爷 出品|产业家 关于云…

饮用水中的六价铬去除工艺

铬是人体必需的微量元素&#xff0c;天然水不含铬&#xff0c;海水中铬的平均浓度为0.05μg/L&#xff0c;饮用水中铬含量更低。 铬在水中主要以三价和六价形式存在&#xff0c;三价的铬是对人体有益的元素&#xff0c;而六价铬是有毒的。由于其毒性之高&#xff0c;已被国家列…

固定转向和行进速度下的车辆轨迹计算方法

游戏车辆固定转向轨迹计算 概述 车辆游戏是我们经常接触到的一类游戏&#xff0c;这里游戏在只用键盘操作时&#xff0c;往往非常不方便。这是因为这一类游戏大部分都是按下按键时转向&#xff0c;释放按键时方向就会自动转正。这种控制方式在实现方面比较容易。但是缺点也很明…

如何实现Canvas图像的拖拽、点击等操作

上一篇Canvas的博文写完后&#xff0c;有位朋友希望能对Canvas绘制出来的图像进行点击、拖拽等操作&#xff0c;因为Canvas绘制出的图像能很好的美化。好像是想做炉石什么的游戏&#xff0c;我也没玩过。 Canvas在我的理解中就好像在一张画布上绘制图像&#xff0c;它只能看到…

MySQL用的在溜,不知道业务如何设计也白搭!!!

MySQL业务设计 作者: 博学谷狂野架构师GitHub&#xff1a;GitHub地址 &#xff08;有我精心准备的130本电子书PDF&#xff09; 只分享干货、不吹水&#xff0c;让我们一起加油&#xff01;&#x1f604; 逻辑设计 范式设计 范式概述 第一范式&#xff1a;当关系模式R的所有属…

浙江省CIO峰会|数据安全+数字化转型,美创特色实践获“年度数字化赋能服务商”

近日&#xff0c;浙江省CIO年度峰会暨数实融合创新发展大会在杭州成功举办。美创科技受邀参加本次峰会&#xff0c;与全省数字化领袖人才共话数字化发展。 对话数字化转型 美创分享能力实践 在本次峰会以“数字化转型的昨天 今天 明天”为主题的论坛对话环节&#xff0c;美创科…