目录
- 一、线性表(拓展)
- 二、列表(list)详解
一、线性表(拓展)
线性表是数据结构里最简单的一种存储结构,专门用来存储逻辑关系为 "一对一"
的数据。根据数据在物理内存中的存储状态,线性表又可以细分成顺序表(顺序存储结构)和链表(链式存储结构)。顺序表和链表还有很多变体,包括静态链表、循环链表、双向链表等。
1.1 线性表(线性存储结构)是什么
线性表又称线性存储结构,是最简单的一种存储结构,专门用来存储逻辑关系为 "一对一"
的数据。在一个数据集中,如果每个数据的左侧都有且仅有一个数据和它有关系,数据的右侧也有且仅有一个数据和它有关系,那么这些数据之间就是 "一对一"
的逻辑关系。举个简单的例子:
如上图所示,在 {1,2,3,4,5}
数据集中,每个数据的左侧都有且仅有一个数据和它紧挨着(除 1 外),右侧也有且仅有一个数据和它紧挨着(除 5 外),这些数据之间就是 "一对一"
的关系。使用线性表存储具有 "一对一"
逻辑关系的数据,不仅可以将所有数据存储到内存中,还可以将 "一对一"
的逻辑关系也存储到内存中。线性表存储数据的方案可以这样来理解,先用一根线将所有数据按照先后次序 串
起来,如下图所示:
上图中,左侧是 串
起来的数据,右侧是空闲的物理空间。将这 一串儿
数据存放到物理空间中,有以下两种方法:
两种存储方式都可以将数据之间的关系存储起来,从线的一头开始捋,可以依次找到每个数据,且数据的前后位置没有发生改变。像上图这样,用一根线将具有 "一对一"
逻辑关系的数据存储起来,这样的存储方式就称为线性表或者线性存储结构。
1.1.1 顺序存储结构和链式存储结构
从之前的图中不难看出,线性表存储数据的实现方案有两种,分别是:
- 像图 3a) 那样,不破坏数据的前后次序,将它们连续存储在内存空间中,这样的存储方案称为顺序存储结构(简称顺序表);
- 像图 3b) 那样,将所有数据分散存储在内存中,数据之间的逻辑关系全靠
"一根线"
维系,这样的存储方案称为链式存储结构(简称链表)。
也就是说,使用线性表存储数据,有两种真正可以落地的存储方案,分别是顺序表和链表。
1.1.2 前驱和后继
在具有 "一对一"
逻辑关系的数据集中,每个个体习惯称为数据元素(简称元素)。例如,下图显示的这组数据集中,一共有 5 个元素,分别是 1、2、3、4 和 5。
此外,很多教程中喜欢用前驱和后继来描述元素之间的前后次序:
- 某一元素的左侧相邻元素称为该元素的
"直接前驱"
,此元素左侧的所有元素统称为该元素的"前驱元素"
; - 某一元素的右侧相邻元素称为该元素的
"直接后继"
,此元素右侧的所有元素统称为该元素的"后继元素"
;
以上图数据中的元素 3 来说,它的直接前驱是 2 ,此元素的前驱元素有 2 个,分别是 1 和 2;同理,此元素的直接后继是 4 ,后继元素也有 2 个,分别是 4 和 5。
1.2 顺序表(顺序存储结构)是什么
顺序表又称顺序存储结构,是线性表的一种,专门存储逻辑关系为 "一对一"
的数据。顺序表存储数据的具体实现方案是:将数据全部存储到一整块内存空间中,数据元素之间按照次序挨个存放。 举个简单的例子,将 {1,2,3,4,5}
这些数据使用顺序表存储,数据最终的存储状态如下图所示:
顺序表的建立: 使用顺序表存储数据,除了存储数据本身的值以外,通常还会记录以下两样数据:
- 顺序表的最大存储容量:顺序表最多可以存储的数据个数;
- 顺序表的长度:当前顺序表中存储的数据个数。
1.3 顺序表的基本操作
1.3.1 顺序表插入元素
向已有顺序表中插入数据元素,根据插入位置的不同,可分为以下 3 种情况:
- 插入到顺序表的表头;
- 在表的中间位置插入元素;
- 尾随顺序表中已有元素,作为顺序表中的最后一个元素;
虽然数据元素插入顺序表中的位置有所不同,但是都使用的是同一种方式去解决,即:通过遍历,找到数据元素要插入的位置,然后做如下两步工作:
- 将要插入位置元素以及后续的元素整体向后移动一个位置;
- 将元素放到腾出来的位置上;
例如,在 {1,2,3,4,5}
的第 3 个位置上插入元素 6,实现过程如下:遍历至顺序表存储第 3 个数据元素的位置,如下图所示:
将元素 3、4 和 5 整体向后移动一个位置,如下图所示:
将新元素 6 放入腾出的位置,如下图所示:
1.3.2 顺序表删除元素
从顺序表中删除指定元素,实现起来非常简单,只需找到目标元素,并将其后续所有元素整体前移 1 个位置即可。后续元素整体前移一个位置,会直接将目标元素删除,可间接实现删除元素的目的。例如,从 {1,2,3,4,5}
中删除元素 3 的过程如下图所示:
1.3.3 顺序表查找元素
顺序表中查找目标元素,可以使用多种查找算法实现,比如说二分查找算法、插值查找算法等。
1.3.4 顺序表更改元素
顺序表更改元素的实现过程是:
- 找到目标元素;
- 直接修改该元素的值;
1.4 链表(链式存储结构)是什么
链表又称单链表、链式存储结构,用于存储逻辑关系为 "一对一"
的数据。和顺序表不同,使用链表存储数据,不强制要求数据在内存中集中存储,各个元素可以分散存储在内存中。例如,使用链表存储 {1,2,3}
, 各个元素在内存中的存储状态可能是:
可以看到,数据不仅没有集中存放,在内存中的存储次序也是混乱的。那么,链表是如何存储数据间逻辑关系的呢?链表存储数据间逻辑关系的实现方案是:为每一个元素配置一个指针,每个元素的指针都指向自己的直接后继元素,如下图所示:
显然,我们只需要记住元素 1 的存储位置,通过它的指针就可以找到元素 2,通过元素 2 的指针就可以找到元素 3,以此类推,各个元素的先后次序一目了然。像上图这样,数据元素随机存储在内存中,通过指针维系数据之间 "一对一"
的逻辑关系,这样的存储结构就是链表。
1.4.1 结点(节点)
很多教材中,也将
"结点"
写成"节点"
,它们是一个意思。
在链表中,每个数据元素都配有一个指针,这意味着,链表上的每个 "元素"
都长下图这个样子:
数据域用来存储元素的值,指针域用来存放指针。数据结构中,通常将上图这样的整体称为结点。也就是说,链表中实际存放的是一个一个的结点,数据元素存放在各个结点的数据域中。举个简单的例子,之前图中的 {1,2,3}
的存储状态用链表表示,如下图所示:
我们习惯将结点中的指针命名为 next,因此指针域又常称为 "Next 域"
。
1.4.2 头结点、头指针和首元结点
1.4.1 结点(节点)
小节中所示的链表并不完整,一个完整的链表应该由以下几部分构成:
- 头指针:一个和结点类型相同的指针,它的特点是:永远指向链表中的第一个结点。上文提到过,我们需要记录链表中第一个元素的存储位置,就是用头指针实现。
- 结点:链表中的节点又细分为头结点、首元结点和其它结点:
- 头结点:某些场景中,为了方便解决问题,会故意在链表的开头放置一个空结点,这样的结点就称为头结点。也就是说,头结点是位于链表开头、数据域为空(不利用)的结点。
- 首元结点:指的是链表开头第一个存有数据的结点。
- 其他节点:链表中其他的节点。
也就是说,一个完整的链表是由头指针和诸多个结点构成的。每个链表都必须有头指针,但头结点不是必须的。例如,创建一个包含头结点的链表存储 {1,2,3}
, 如下图所示:
再次强调,头指针永远指向链表中的第一个结点。换句话说,如果链表中包含头结点,那么头指针指向的是头结点,反之头指针指向首元结点。
1.5 单链表的基本操作
1.5.1 链表插入元素
同顺序表一样,向链表中增添元素,根据添加位置不同,可分为以下 3 种情况:
- 插入到链表的头部,作为首元节点;
- 插入到链表中间的某个位置;
- 插入到链表的最末端,作为链表中最后一个结点;
对于有头结点的链表,3 种插入元素的实现思想是相同的,具体步骤是:
- 将新结点的 next 指针指向插入位置后的结点;
- 将插入位置前结点的 next 指针指向插入结点;
例如,在链表 {1,2,3,4}
的基础上分别实现在头部、中间、尾部插入新元素 5,其实现过程如下图所示:
注意: 链表插入元素的操作必须是先步骤 1,再步骤 2;反之,若先执行步骤 2,除非再添加一个指针,作为插入位置后续链表的头指针,否则会导致插入位置后的这部分链表丢失,无法再实现步骤 1。于没有头结点的链表,在头部插入结点比较特殊,需要单独实现。
和 2)、3) 种情况相比,由于链表没有头结点,在头部插入新结点,此结点之前没有任何结点,实现的步骤如下:
- 将新结点的指针指向首元结点;
- 将头指针指向新结点。
1.5.2 链表删除元素
从链表中删除指定数据元素时,实则就是将存有该数据元素的节点从链表中摘除。对于有头结点的链表来说,无论删除头部(首元结点)、中部、尾部的结点,实现方式都一样,执行以下三步操作:
- 找到目标元素所在结点的直接前驱结点;
- 将目标结点从链表中摘下来;
- 手动释放结点占用的内存空间;
从链表上摘除目标节点,只需找到该节点的直接前驱节点 temp,执行如下操作:
temp->next=temp->next->next;
例如,从存有 {1,2,3,4}
的链表中删除存储元素 3 的结点,则此代码的执行效果如下图所示:
对于不带头结点的链表,需要单独考虑删除首元结点的情况,删除其它结点的方式和上图完全相同,如下图所示:
1.5.3 链表查找元素
在链表中查找指定数据元素,最常用的方法是:从首元结点开始依次遍历所有节点,直至找到存储目标元素的结点。如果遍历至最后一个结点仍未找到,表明链表中没有存储该元素。
1.5.4 链表更新元素
更新链表中的元素,只需通过遍历找到存储此元素的节点,对节点中的数据域做更改操作即可。
1.6 顺序表和链表的区别(优缺点)详解
顺序表和链表是线性表的两种实现方式,都用来存储逻辑关系为 "一对一"
的数据。顺序表和链表最本质上的不同,在于它们存储数据的方式,或者说存储结构不同。顾名思义,顺序表是将数据按照次序存储起来,并且数据集中存放在内存中;链表是将数据通过指针 "链"
起来,各个数据元素可以随意存储在内存中。顺序表和链表在存储结构上的区别,如下图所示:
不同的存储结构,导致了顺序表和链表有以下几个方面的区别。
1.6.1 开辟内存空间的方式
顺序表需要将所有数据集中存放在内存空间中,因此往往会一次性申请大量的空间,打好提前量,以备后续使用。链表存储数据时,讲究用多少内存就申请多少,后续需要可以再申请。也就是说,在申请内存空间这件事情上,顺序表需要未雨绸缪,而链表只顾眼下即可。实际开发中,当数据量不确定,又或者内存 "碎片化"
严重,无法申请足够大的一整块空间,就可以尝试用链表存储数据。
所谓
"内存碎片"
,指的是那些因容量很小(1KB甚至更小)无法再利用的内存空间。
1.6.2 空间利用率
关于顺序表和链表在空间利用率上的对比,有两种完全不同的说法。一种说法是,顺序表比链表更浪费内存空间。因为顺序表需要一次性申请足够的内存,当不确定数据量的前提下,很可能出现 "申请了过大的内存,其中很多空间无法有效利用"
的情况。相比之下,链表每次申请的内存空间都能充分利用上,不会造成空间的浪费。另一种说法是,链表比顺序表更浪费内存空间。分别用顺序表和链表存储 {1,2,3,4}
, 和顺序表相比,链表的每个结点除了存储数据本身,还要存储后继结点的地址。存储相同数量的数据,链表占用的内存空间比顺序表多。不仅如此,由于链表将数据分散存储在内存中,可能导致内存中产生更多的 "碎片"
。
以上两种说法,完全是从不同的角度分析问题。如果顺序表申请的内存空间刚好都能利用上,那么顺序表的空间利用率比链表高;反之,如果顺序表申请的内存空间无法充分利用,那么链表的空间利用率会更高。
1.6.3 时间复杂度
基于数据不同的存储状态,顺序表更擅长访问、遍历数据,链表更擅长插入、删除数据。通常情况下,我们习惯用数组实现顺序表。数组中存储的元素可以直接通过下标访问,不需要遍历数组,所以顺序表访问目标元素的时间复杂度最低可以达到 O(1)。反观在链表中访问目标元素,由于数据分散存储在内存中,只能遍历链表(从头指针开始往后捋),直至找到目标元素,所以链表中访问目标元素的时间复杂度为 O(n)。退一万步讲,同样是做遍历数据的操作,时间复杂度都为 O(n),顺序表的执行效率也略高于链表。道理很简单,顺序表中的数据是集中存放的,CPU 只需要找到第一个元素,所有元素就都找到了。而链表中的数据是分散存储在内存中的,元素之间可能相隔十万八千里,CPU 找到第一个元素后,还要通过指针寻找下一个元素。在实现插入、删除元素的操作上,链表比顺序表更有优势。链表中元素之间的逻辑关系是要指针维系的,插入、删除元素时,更改指针的指向即可,不需要移动元素的存储位置,时间复杂度最低可以达到 O(1)。而在顺序表中,除非在顺序表的尾部插入元素,又或是删除顺序表最后一个元素,否则都需要移动多个元素的存储位置,时间复杂度为 O(n)。总的来说,顺序表和链表的存储结构不同,造就了它们擅长做不同的操作,适用于不同的应用场景。
1.6.4 总结
顺序表和链表的区别在于它们的存储结构不同。顺序表将所有数据集中存放在内存中,擅长访问、遍历数据,在数据量提前预知的情况下,空间利用率更高。链表将数据分散存放在内存中,擅长插入、删除数据,在数据量无法预知的情况下,空间利用率更高。
二、列表(list)详解
对于歌曲列表大家一定很熟悉,在列表中记录着要播放的歌曲名称,如下图所示的手机 App 歌曲列表页面。
Python 中的列表和歌曲列表类似,也是由一系列按 特定顺序排列(可以使用索引) 的元素组成的。它是 Python 中内置的 可变序列。 在形式上,列表的所有元素都放在一对中括号 []
中,两个相邻元素间使用逗号 ,
分隔。在内容上,可以将整数、实数、字符串、列表、元组等任何类型的内容放入到列表中,并且同一个列表中,元素的类型可以不同,因为它们之间没有任何关系。由此可见,Python 中的列表是非常灵活的,这一点与其他语言是不同的。Python 列表是线性的数据结构,采用顺序表实现。
列表是非常重要的数据结构,对其内存结构和操作方法必须烂熟于心。
2.1 初始化
列表不能一开始就定义大小
2.1.1 []–直接创建列表
在 Python 中,可以直接通过中括号 []
创建列表,创建列表时,在中括号的内容放置由逗号分隔的元素。其语法格式如下:
listname = [element1,element2,element3,…,elementn]
参数说明:
- listname 表示列表的名称,可以是任何符合 Python 命名规则的标识符。
- element1、element2、element3、elementn:表示列表中的元素,个数没有限制,并且只要是 Python 支持的数据类型就可以。
【示例1】通过“=”符号定义列表。
num = [7, 14, 21, 28, 35, 42, 49, 56, 63] # 定义数值型列表
verse = ['埃及金字塔', '巴比伦空中花园', '宙斯神像', '亚历山大灯塔'] # 定义字符型列表
python = ['优雅', "明确", '''简单'''] # 定义注释字符型列表
print('num列表内容为:', num)
print('verse列表内容为:', verse)
print('python列表内容为:', python)
【示例2】通过“=”符号定义二维列表。
# 定义二维列表
untitle = ['Python', 28, '人生苦短,我用Python', ['爬虫', '自动化运维', '云计算', 'Web开发']]
print('untitle列表内容为:', untitle)
【示例3】通过列表推导式生成列表。
import random
list1 = [i for i in range(10)] # 创建0~10之间(不包括10)的数字列表
print(list1)
list2 = [i for i in range(10, 100, 10)] # 创建10~100之间(不包括100)的整十数列表
print(list2)
# 创建10个4位数的随机数列表
list3 = [random.randint(1000, 10000) for i in range(10)]
print(list3)
list4 = [i for i in '壹贰叁肆伍'] # 将字符串转换为列表
print(list4)
# 生成所有单词首字母列表
list5 = [i[0] for i in ['Early', 'bird', 'gets', 'the', 'worm']]
print(list5)
# 将原列表中的数字折半后生成新的列表
list6 = [int(i * 0.5) for i in [1200, 5608, 4314, 6060, 5210]]
print(list6)
list7 = [i for i in ('Early', 'bird', 'gets', 'the', 'worm')] # 通过元组生成新的列表
print(list7)
# 将字典的Key生成新的列表
list8 = [key for key in {'qq': '84978981', 'mr': '84978982', 'wgh': '84978980'}]
print(list8)
list9 = [key for key in {1, 3, 5, 7, 9}] # 通过集合生成有序列表
print(list9)
2.1.2 list() 函数–创建列表
list() 函数用于将序列转换成列表类型并返回一个数据列表,其语法格式如下:
list(iterable=(), /)
If no argument is given, the constructor creates a new empty list.
The argument must be an iterable if specified.
参数说明:
- iterable:表示可以转换为列表的数据,其类型可以是 range 对象、字符串、列表、元组、字典或者其他可迭代类型的数据。
- 返回值:列表。
list() 函数可以传入一个可迭代对象,如字符串、元组、列表、range 对象等,结果将返回可迭代对象中元素组成的列表。list() 函数也可以不传入任何参数,结果返回一个空列表。
【示例1】创建列表。例如通过range对象直接创建一个列表,示例代码如下:
range_list = list(range(10, 20, 2)) # 通过range对象创建列表
print('通过range对象创建的列表内容为:', range_list)
print(list()) # 不传入参数,创建一个空列表
print(list('一二三四')) # 将字符串转换为列表
print(list(('壹', '贰', '叁', '肆'))) # 将元组转换为列表
print(list(['Ⅰ', 'Ⅱ', 'Ⅲ', 'Ⅳ'])) # 参数为列表则原样输出
print(list()) # 不传入参数,创建一个空列表
print(list('Python')) # 将字符串转换为列表
print(list(('a', 'b', 'c', 'd'))) # 将元组转换为列表
print(list(['Forever', 'I Need You', 'Alone', 'Hello'])) # 参数为列表则原样输出
print(list(range(1, 11))) # 将range对象转换为列表
【示例2】将字典转换为列表。使用list()函数将字典转换为列表,示例代码如下:
dictionary = {'Python': 98, 'Java': 80, 'C语言': 75} # 定义字典
print(list(dictionary)) # 使用list()函数转换为列表
提示:list()函数的参数为字典时,会返回字典的key组成的列表。如果需要将字典中的values()转换为列表时可以使用如下代码:
print(list(dictionary.values())) # 将字典中values转换为列表
2.2 len函数–获取对象的长度或项目个数
len() 函数的主要功能是获取一个(字符、列表、元组等)可迭代对象的长度或项目个数。其语法格式如下:
参数说明:
- 参数s:要获取其长度或者项目个数的对象。如字符串、元组、列表、字典等;
- 返回值:对象长度或项目个数。
示例:
# 1.获取字符串的长度
# 字符串中每个符号仅占用一个位置,所以该字符串长度为34
str1 = '今天会很残酷,明天会更残酷,后天会很美好,但大部分人会死在明天晚上。'
# 在获取字符串长度时,空格也需要占用一个位置,所以该字符串长度为11
str2 = 'hello world'
print('str1字符串的长度为:', len(str1)) # 打印str1字符串长度
print('str2字符串的长度为', len(str2)) # 打印str2字符串长度
# 打印str2字符串去除空格后的长度
print('str2字符串去除空格后的长度为:', len(str2.replace(' ', '')))
# 2.获取列表长度
# 在获取列表长度时,len函数不会在意列表内元素的类型
l1 = [1, 2, 3, 4, '123', 2.15]
# 同时定义两个元素类型不同的列表
list1, list2 = [1, 2, 3], ['a', 'b', 'c']
list3 = ['库里', '杜兰特', '詹姆斯', '哈登', '威少'] # 定义一个列表
print('list列表的长度为 : ', len(l1)) # 打印list列表长度
print('list1列表的长度为: ', len(list1)) # 打印list1列表长度
print('list2列表的长度为:', len(list2)) # 打印list2列表长度
print('共有', len(list3), '名球员') # 获取列表元素个数
# 获取列表下标为1~4范围的长度,不包含下标为4的元素
print('列表中指定元素范围的长度为:', len(l1[1:4]))
# 3.获取元组长度
tuple1 = (1, 11, 111, 1111, 11111) # 创建元素长度不同的元组
print('tuple1元组长度为:', len(tuple1)) # 打印tuple1元组长度
print('元组中指定元素范围的长度为:', len(tuple1[1:3])) # 打印tuple1元组指定元素范围的长度
# 创建星期英文元组
tuple2 = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday')
print('tuple2元组中元素长度最大为:', max(len(i) for i in tuple2)) # 打印tuple2元组中长度最大值
# 打印tuple2元组中长度最大的元素
print('tuple2元组中长度最大的元素为:', max(tuple2, key=lambda i: len(i)))
# 打印tuple2元组中长度最小的元素
print('tuple2元组中长度最小的元素为:', min(tuple2, key=lambda i: len(i)))
# 创建国际旅游胜地前四名的二维元组
tuple3 = (('威尼斯', 1), ('阿姆斯特丹运河', 2), ('马尔代夫', 3), ('迪拜', 4))
print('二维元组tuple3的长度为:', len(tuple3)) # 打印二维元组的长度
# 打印二维元组中旅游胜地名称最长的元组
print('旅游胜地名称最长的元组为:', max(tuple3, key=lambda i: len(i[0])))
# 4.获取字典长度
# 人物基本信息
dict_name = {'Name': 'Aaron', 'Age': 18, 'height': 1.72, 'weight': 55, 'sex': 'g'}
print('dict_name字典长度度为:', len(dict_name)) # 打印dict_name字典长度
# 使用dict()函数创建一个字典
dictionary = dict((('邓肯', '石佛'), ('吉诺比利', '妖刀'), ('帕克', '跑车')))
print('字典:', dictionary) # 输出字典
print('字典中的元素个数为:', len(dictionary)) # 获取字典中的元素个数
# 某淘汰比赛中,前五名的参赛人员与对应编号
dict_info = {'17123': {'name': 'Lee'},
'121234': {'name': 'Jeff'},
'153': {'name': 'Rodriguez'},
'16423': {'name': 'Jackson'},
'1344349': {'name': 'Williams'}}
# 打印参赛编号最长的那位参赛者名称
print('获取数据中参赛编号最长的那位参赛者名称:',
max(dict_info.items(), key=lambda i: len(i[0]))[1].get('name'))
# 打印赛者名称最长的那位参赛者名称
print('获取参赛者名称最长的那位参赛者名称:',
max(dict_info.items(), key=lambda i: len(i[1].get('name')))[1].get('name'))
注意: 当 len() 函数中的参数不是一个可迭代对象时,将出现类型错误的提示信息。示例代码如下:
其他示例:
import re
import os
# 1.读取txt文件并计算每行的长度
file1 = open('len.txt', 'r', encoding='utf8') # 以读取的方式打开txt文件
for value1 in file1.readlines(): # 循环遍历每行文字
word1 = value1.replace('\n', '') # 去除换行符
print(word1) # 打印每行文字
len1 = len(word1) # 获取每行文字长度
print(len1) # 打印长度
file1.close() # 关闭文件
# 2.计算一个字符串中包含"aeiou"这5个字符的数量
def count_vowels(s):
# 使用正则表达式匹配所有包括aeiou的字符,然后计算长度
return len(re.findall(r'[aeiou]', s, re.IGNORECASE))
print(count_vowels('foobar'))
print(count_vowels('gym'))
# 3.判断列表中的元素是否有重复的
def all_unique(lst):
# 先将列表转化为集合,利用集合去重功能,删除重复元素,然后再和原来的列表对比
return len(lst) == len(set(lst))
x = [1, 1, 2, 2, 3, 2, 3, 4, 5, 6]
y = [1, 2, 3, 4, 5]
print(all_unique(x))
print(all_unique(y))
# 4.计算字符串的字节长度
def byte_size(s):
return len(s.encode('utf-8')) # 使用encode()函数设置编码格式
print(byte_size('Hello World'))
print(byte_size('人生苦短,我用Python')) # 在utf-8编码格式下,一个中文占3个字节。
# 5.判断文件内容是否为空
python_text = open('python.txt', 'r', encoding='utf8') # 以读取模式打开文本文件
text = python_text.read() # 读取文件内容
if len(text) == 0: # 判断文件内容长度是否为0
print('该文件为空!')
else:
print('文件内容为:', text) # 打印文件内容
# 额外:在读取文件时,除了通过len函数,去判断文件的内容是否为空,还可以使用os.path.getsize的方法获取文件的字节数,
# 然后通过文件的字节数来判断文件内容是否为空。示例代码如下:
text = 'python.txt' # 文件路径
print('文件的字节数为:', os.path.getsize(text))
2.2 索引
列表中的每一个元素都有一个编号, 也称为索引(下标)。这个索引是从 0
开始递增的,即下标为 0
表示 第一个
元素,下标为 1
表示 第二个
元素,依此类推。如下图所示:
Python 比较神奇,它的索引可以是负数。这个索引从右向左计数,也就是从最后一个元素开始计数,即 最后一个元素
的索引值是 -1
,倒数 第二个元素
的索引值为 -2
,依此类推。如下图所示:
在采用负数作为索引值时,是从 -1
开始的,而不是从 0
开始的,即最后一个元素的下标为 -1
,这是为了防止与第一个元素重合。通过索引可以访问列表中的任何元素,list[index],index 就是索引,使用 []中括号 访问。示例:
name_list = ['Amo', 'Jerry', 'Paul', 'Ben', 'Crystal']
print(name_list[0]) # 访问列表中的第一个元素 Amo
print(name_list[3]) # 访问列表中的第四个元素 Ben
print(name_list[-3]) # 访问列表中倒数第三个元素 Paul
如果列表有元素,索引范围 [0,列表长度-1]
或者是 [-列表长度,-1]
,正、负索引不可以超界,否则引发异常 IndexError,示例:
使用索引定位访问元素的时间复杂度为O(1),这是最快的方式,是列表最好的使用方式。
2.3 查询
2.3.1 index() 方法–获取指定元素首次出现的索引
使用列表对象的 index() 方法可以获取指定元素在列表中首次出现的位置(即索引)。其语法格式如下:
# ipython
In [9]: listname.index?
Signature: listname.index(value, start=0, stop=9223372036854775807, /)
Docstring:
Return first index of value.
Raises ValueError if the value is not present.
Type: builtin_function_or_method
# python31011.chm文档
s.index(x[, i[, j]])
index of the first occurrence of x in s (at or after index i and before index j)
参数说明:
- listname:表示列表的名称。
- value:表示要查找的值。
- start:可选参数,指定起始的查找位置(包含),默认为0,即从索引为0的位置开始查找。
- stop:可选参数,指定查找的截止位置(不包含),默认为9223372036854775807。
- 返回值:首次出现的索引值,如果没有找到将抛出异常。
【示例1】判断指定元素首次出现的位置。创建一个列表,然后应用列表对象的index()方法判断元素“纳达尔”首次出现的位置,示例代码如下:
champion = ['费德勒', '德约科维奇', '纳达尔', '穆雷', '瓦林卡', '西里奇'] # 原列表
# 用index()方法获得列表中"纳达尔"首次出现的位置的索引,结果赋给position
position = champion.index('纳达尔')
print('纳达尔首次出现的位置的索引为:', position) # 2
【示例2】判断混合型列表中指定元素出现的位置。创建一个混合类型元素的列表,然后应用列表对象的index()方法判断指定元素出现的位置,示例代码如下:
city = ['杭州', ('扬州', 4, '苏州'), [16, '株洲', '徐州'], 32, '郑州'] # 原列表
# 用index()方法获得列表中指定元素首次出现的位置的索引,结果赋给position
position = city.index(('扬州', 4, '苏州'))
print('指定元素首次出现位置的索引为:', position) # 1
说明:如果是混合类型的列表,应用列表对象的index()方法判断元素"苏州"首次出现的位置时,将只判断列表中字符串类型的元素,出现在元组类型元素里的"苏州"将不被判断。示例代码如下:
city = ['杭州', ('扬州', 4, '苏州'), [16, '株洲', '徐州'], 32, '郑州'] # 原列表
# 用index()方法获得列表中指定元素首次出现的位置的索引,结果赋给position
position = city.index('苏州')
print('判断苏州元素首次出现位置的索引为:', position)
执行上面的代码,将提示下图所示的错误:
【示例3】使用del关键字删除指定索引的元素。
goal = '宙斯神像' # 需要删除的元素
verse = ['埃及金字塔', '巴比伦空中花园', '宙斯神像', '亚历山大灯塔'] # 定义字符型列表
del verse[verse.index(goal)] # 删除指定索引的元素
print('删除指定元素后列表为:', verse)
【示例4】指定区间内元素首次出现的位置。示例代码如下:
my_list = [10, 20, 30, 20, 40, 50]
# 查找第一次出现 20 的索引,范围是从索引 2 到 5(不包含 5)
index_20_with_end = my_list.index(20, 2, 5)
print("从索引 2 到 4 查找 20 的索引是:", index_20_with_end) # 输出: 3
# 查找第一次出现 20 的索引,范围是从索引 2 到 6(包含 5)
index_20_with_inclusive_end = my_list.index(20, 2, 6)
print("从索引 2 到 5 查找 20 的索引是:", index_20_with_inclusive_end) # 输出: 3
# 尝试查找不存在的元素 50 的索引,范围是从索引 2 到 5(不包含 5)
try:
index_50_with_end = my_list.index(50, 2, 5)
except ValueError:
print("元素 50 不在索引 2 到 4 范围内") # 输出: 元素 50 不在索引 2 到 4 范围内
# 查找元素 50 的索引,范围是从索引 2 到 6(包含 5)
index_50_with_inclusive_end = my_list.index(50, 2, 6)
print("从索引 2 到 5 查找 50 的索引是:", index_50_with_inclusive_end) # 输出: 5
2.3.2 count() 方法–获取指定元素出现的次数
使用列表对象的 count() 方法可以获取指定元素在列表中出现的次数。其语法格式如下:
# python31011.chm文档
s.count(x) total number of occurrences of x in s
# ipython
In [12]: listname.count?
Signature: listname.count(value, /)
Docstring: Return number of occurrences of value.
Type: builtin_function_or_method
参数说明:
- listname:表示列表的名称。
- value:表示要获取的值。
- 返回值:元素在列表中出现的次数。
【示例1】判断列表中指定元素出现的次数。创建一个列表,应用列表对象的count()方法判断元素“乒乓球”出现的次数,示例代码如下:
play = ['乒乓球', '跳水', '女排', '举重', '射击', '体操', '乒乓球'] # 原列表
num = play.count('乒乓球') # 用count()方法获得列表中“乒乓球”出现的次数,结果赋给num
print('乒乓球出现的次数为:', num) # 2
【示例2】判断混合类型列表中指定元素出现的次数。如果是混合类型的列表[99,[‘刘备’,99,‘袁绍’],(99,‘孙权’,‘刘表’),‘曹操’,99],应用列表对象的count()方法判断“99”元素出现的次数时,将只统计列表中数字类型的元素,出现在列表类型元素或元组类型元素里的“99”将不被计数。示例代码如下:
monkey = [99, ['刘备', 99, '袁绍'], (99, '孙权', '刘表'), '曹操', 99] # 原列表
num = monkey.count(99) # 用count()方法获得列表中“99”出现的次数,结果赋给num
print('99出现的次数为:', num) # 2
【示例3】判断二维列表中指定元素出现的次数。创建一个二维列表作为数据,然后循环遍历列表中的元素并判断列表中是否包含list类型数据,如果包含则获取该列表中指定元素出现的次数,最后统计指定元素出现的总次数即可。示例代码如下:
# 某公司迟到点名数据
two_list = ['小赵', '老钱', '老孙', '小李', ['小赵', '老周', '老孙', '小王'], ['老吴', '老吴', '小冯', '小赵']]
count = 0 # 叠加列表元素出现的次数
goal = '小赵' # 需要查找的元素
for i in two_list: # 循环遍历列表元素
if isinstance(i, list): # 判断列表中元素是否还有列表
count += i.count(goal) # 如果有列表则获取该列表中指定元素出现的次数
# 最后打印整个二维列表中指定元素出现的次数 3
print(goal, '元素在二维列表中出现了', two_list.count(goal) + count, '次!')
【示例4】获取列表中不同类型元素出现的次数。
ranking_list = [{1: 'Java'}, [2, 'C'], (3, 'Python'), {1: 'Java'}] # 多类型元素的列表
print(ranking_list.count(ranking_list[0])) # 获取列表中指定元素的数量 2
print(ranking_list.count({1: 'Java'})) # 获取列表中指定字典数据的数量 2
print(ranking_list.count([2, 'C'])) # 获取列表中指定列表数据的数量 1
print(ranking_list.count((3, 'Python'))) # 获取列表中指定元组数据的数量1
index 和 count 方法都是 O(n),随着列表数据规模的增大,而效率下降,能不用则不用。
2.4 修改
修改列表中的元素只需要通过索引获取该元素,然后再为其重新赋值即可。例如,定义一个保存3个元素的列表,然后修改索引值为2的元素,代码如下:
verse = ['长亭外', '古道边', '芳草碧连天']
print(verse)
verse[2] = '一行白鹭上青天' # 修改列表的第3个元素
print(verse)
2.5 增加单个元素
2.5.1 append() 方法–添加列表元素
列表对象的 append() 方法,是用于向列表的末尾追加元素。其语法格式如下:
# ipython
In [13]: listname.append?
Signature: listname.append(object, /)
Docstring: Append object to the end of the list.
Type: builtin_function_or_method
参数说明:
- listname:表示要添加元素的列表名称。
- obj:表示要添加到列表末尾的对象。
- 没有新的列表产生,就地修改。定位时间复杂度是 O(1)
【示例1】 向列表中添加指定元素。定义一个包括5个元素的列表,然后应用append()方法向该列表的末尾再添加一个元素,示例代码如下:
building = ['醉翁亭', '放鹤亭', '喜雨亭', '陶然亭', '爱晚亭'] # 原列表
print('原列表:', building) # 打印原列表
building.append('湖心亭') # 向列表的末尾添加元素
print('添加元素后的列表:', building) # 打印添加元素后的列表
【示例2】 向列表中添加类型不同的元素。append()方法向列表末尾添加的元素类型可以与原列表中的元素类型不同。示例代码如下:
building = ['刀', '枪', '剑', '戟']
print('原列表:', building)
building.append(['scoop', 50]) # 向列表中添加列表类型的元素
print('添加列表类型元素后的新列表:', building)
building.append((100, 200)) # 向列表中添加元组类型的元素
print('添加元组类型元素后的新列表:', building)
building.append(9) # 向列表中添加数值类型的元素
print('添加数值类型元素后的新列表:', building)
【示例3】 将txt文件中的信息添加至列表中。首先需要以读取文件的方式打开目标文件,然后循环遍历文件中每行内容,再将每行内容添加至指定的列表中。示例代码如下:
result = [] # 保存txt每行数据
print('txt文件内信息如下:')
# 以读取模式打开txt文件
with open('user-name.txt', 'r') as f:
for line in f: # 循环遍历每行信息
print(line.strip('\n'))
result.append(line.strip('\n')) # 将txt文件中每行信息添加至列表中
print('提取后的信息为:', result) # 打印提取后的信息
【示例4】根据列表字符元素首字母对字符元素分类。创建列车车次的列表数据,再分别创建一个保存分类后数据的列表与保存车次分类首字母的集合。通过for循环获取列车车次数据中有哪几种首字母,然后根据首字母对车次信息进行分类即可。示例代码如下:
# 列车车次数据
train = ['D74', 'D20', 'G240', 'D102', 'Z158', 'G394', 'K1304', 'D30',
'D22', 'G384', 'G382', 'D4606', 'K350', 'K340',
'Z62', 'Z64', 'K266', 'Z118']
result = [] # 保存分类后数据
type_set = set() # 保存分类首字母
for i in train: # 遍历车次信息
type_set.add(i[0]) # 将首字母添加至集合中
print('列车车次共分为', len(type_set), '类')
for index, z in enumerate(type_set): # 遍历车次分类的首字母
result.append([]) # 根据分类数量,向分类后数据列表中添加空列表
for t in train: # 循环遍历车次信息
if t[0] == z: # 如果车次信息首字母相同
result[index].append(t) # 将该车次信息添加至当前首字母分类中
print('分类后数据如下:')
for r in result: # 循环遍历分类后数据
print(r)
【示例5】通过循环遍历筛选列表中的重复元素。循环遍历带有重复元素的列表,然后判断用于保存筛选后的数据列表中是否存在当前遍历的元素,不存在就将该元素添加至保存筛选后的数据列表中,最后打印筛选后的列表内容。代码如下:
info_list = [1, 2, 2, 3, 4, 4, 5, 5, 5, 6, 7, 8, 9] # 重复元素的列表数据
new_list = [] # 保存筛选后的数据列表
for i in info_list: # 遍历重复元素的列表
if i not in new_list: # 判断元素是否存在new_list列表中
new_list.append(i) # 不存在就添加进new_list列表中
print(new_list) # 打印筛选后的列表[1, 2, 3, 4, 5, 6, 7, 8, 9]
【示例6】通过列表推导式的方式筛选列表中的重复元素。
info_list = [1, 2, 2, 3, 4, 4, 5, 5, 5, 6, 7, 8, 9] # 重复元素的列表数据
new_list = [] # 保存筛选后的数据列表
# 通过列表推导式的方式筛选列表中的重复元素
[new_list.append(i) for i in info_list if i not in new_list]
print(new_list) # 打印筛选后的列表[1, 2, 3, 4, 5, 6, 7, 8, 9]
【示例7】随机生成双色球7个号码。在实现双色球7个号码的获取时,首先在while循环中从1~33的数字内依次随机生成6个红色号码并将号码添加至列表当中,然后再从1~16的数字中随机生成1个蓝色号码添加列表后跳出while循环,输出列表中随机生成的双色球7个号码。示例代码如下:
import random # 导入随机模块
number_list = [] # 保存双色球中奖号码
# 循环随机抽取号码
while True:
red_number = random.randint(1, 33) # 随机生成红球号码
if red_number not in number_list:
number_list.append(red_number) # 将选取的红球号码添加至列表
if len(number_list) == 6:
blue_number = random.randint(1, 16) # 随机生成红球号码
number_list.append(blue_number) # 将选取的蓝球号码添加至列表
break # 篮球号码添加完成以后跳出循环
print(number_list) # [26, 5, 21, 31, 20, 14, 7]
2.5.2 insert() 方法–向列表的指定位置插入元素
如果想要向列表的指定位置插入元素,可以使用列表对象的 insert() 方法实现。其语法格式如下:
In [18]: listname.insert?
Signature: listname.insert(index, object, /)
Docstring: Insert object before index.
Type: builtin_function_or_method
参数说明:
- listname:表示原列表。
- index:表示对象 obj 需要插入的索引值。
- obj:表示要插入列表中的对象。
- 没有新的列表产生,就地修改。定位时间复杂度是O(1),如果是在中间插入,会造成数据的挪动,当列表规模比较大时,会影响性能
【示例1】向列表的指定位置添加元素。定义一个包括5个元素的列表,然后应用insert()方法向该列表的第2个位置处添加一个元素,示例代码如下:
building = ['北京', '长安', '洛阳', '金陵', '汴梁'] # 定义原列表
print('原列表:', building)
building.insert(1, '杭州') # 向原列表的第2个位置处添加元素
print('新列表:', building)
building.insert(333, '重庆') # 向原列表的第334个位置处添加元素
print('新列表:', building) # 超越上界,尾部追加
building.insert(-66, '上海') # 向原列表的第-66个位置处添加元素
print('新列表:', building) # 超越下界,头部追加
2.6 增加多个元素
2.6.1 extend() 方法–将序列的全部元素添加到另一列表中
extend() 方法是向列表中添加一个元素,而 extend() 方法可以实现将一个序列中的全部元素添加到列表中。其语法格式如下:
In [19]: listname.extend?
Signature: listname.extend(iterable, /)
Docstring: Extend list by appending elements from the iterable.
Type: builtin_function_or_method
参数说明:
- listname:表示要添加元素的列表名称。
- iterable:表示要被添加的可迭代对象。语句执行后,iterable 的内容将追加到 listname 的后面。
- 就地修改,本列表自身扩展
【示例1】将序列中的全部元素添加至列表。定义一个包括2个元素的,名为color的列表,然后应用extend()方法将另外3个序列中的元素添加到color列表的末尾,示例代码如下:
color = ['红', '橙'] # 定义原列表
print('原列表:', color)
color.extend(['黄', '绿']) # 将列表['黄','绿']中的元素全部添加到color的末尾
print('添加列表元素:', color)
color.extend(('青', '蓝')) # 将元组('青','蓝')中的元素全部添加到color的末尾
print('添加元组元素:', color)
color.extend('紫黑白') # 将字符串'紫黑白'中的元素全部添加到color的末尾
print('添加字符串元素:', color)
【示例2】向列表中添加混合类型的序列。通过extend()方法向列表末尾添加混合类型的序列。示例代码如下:
building = ['滕王阁', '蓬莱阁', '天心阁', '天一阁'] # 定义原列表
print('原列表:', building)
# 将列表['tall',(6,9),['?','!'],300]中的全部元素添加到building的末尾
building.extend(['tall', (6, 9), ['?', '!'], 300])
print('新列表:', building)
说明:如果通过extend()方法向列表中添加字典数据时,在默认情况下只会将字典中的key值添加至列表当中。示例代码如下:
surname = ['赵', '钱', '孙', '李'] # 定义列表
surname.extend({'1': '周'}) # 向列表中添加字典数据
print('新列表内容为:', surname) # 打印添加后的列表内容
【示例3】将二维列表转换为一维列表。遍历二维列表中的子列表,然后将子列表中的元素添加至一维列表当中,代码如下:
two_list = [[1, 2], [3, 4], [5, 6], [7, 8]] # 创建二维列表
one_list = [] # 一维列表
for i in two_list: # 便利二维列表中的元素
one_list.extend(i) # 将二维列表中子列表内的元素添加值一维列表内
print(one_list) # 打印一维列表
【示例4】将同时包含一维和二维的列表转换为一维列表。在一个二维列表中,既有普通的数值类型元素,也有列表元素,现在需要将该二维列表转化为一维列表,代码如下:
def spread(arg):
ret = []
for i in arg:
if isinstance(i, list): # 如果元素是列表,则使用extend方法将每个元素添加到列表
ret.extend(i)
else: # 如果元素不是列表,则使用append方法追加到原列表
ret.append(i)
return ret # 返回一维列表
print(spread([1, 2, 3, [4, 5, 6], [7], 8, 9]))
2.6.2 序列加法
在 Python 中,支持两种相同类型的序列相加操作,即将两个序列进行连接,不会去除重复的元素,使用加(+)运算符实现。例如,将两个列表相加,可以使用下面的代码:
nba1 = ["德怀特・霍华德", "德维恩・韦德", "凯里・欧文", "保罗・加索尔"]
nba2 = ["迈克尔・乔丹", "比尔・拉塞尔", "卡里姆・阿布杜尔・贾巴尔", "威尔特・张伯伦",
"埃尔文・约翰逊", "科比・布莱恩特", "蒂姆・邓肯", "勒布朗・詹姆斯", "拉里・伯德",
"沙奎尔・奥尼尔"]
# 将两个列表连接起来,产生新的列表,原列表不变
# 本质上调用的是魔术方法__add__()方法
print(nba1 + nba2)
说明: 在进行序列相加时,相同类型的序列是指同为列表、元组、集合等,序列中的元素类型可以不同。例如,下面的代码也是正确的:
但是不能将列表和元组相加,也不能将列表和字符串相加。例如,下面的代码就是错误的:
2.6.3 序列乘法
在 Python 中,使用数字 n 乘以一个序列会生成新的序列。新序列的内容为原来序列被重复 n 次的结果。例如,下面的代码,将实现把一个序列乘以 3 生成一个新的序列并输出,从而达到 "重要事情说三遍"
的效果。
phone = ["华为Mate 10", "Vivo X21"]
# ['华为Mate 10', 'Vivo X21', '华为Mate 10', 'Vivo X21', '华为Mate 10', 'Vivo X21']
print(phone * 3)
在进行序列的乘法运算时,还可以实现初始化指定长度列表的功能。例如下面的代码,将创建一个长度为 5 的列表,列表的每个元素都是 None,表示什么都没有。
empty_list = [None] * 5
# [None, None, None, None, None]
print(empty_list)
这个重复操作看似好用,如果原理掌握不好,但非常危险。示例:
x = [1] * 3
x[0] = 100
print(x) # 结果是什么 x==>[100,1,1]
y = [[1]] * 3
print(y) # 结果是什么 y==>[[1], [1], [1]]
y[0] = 100
print(y) # 结果是什么 y==>[100, [1], [1]]
y[1][0] = 200
print(y) # 结果是什么 y==>[100, [200], [200]]
在 Python 中一切皆对象,而对象都是引用类型,可以理解为一个地址指针指向这个对象。但是,字面常量字符串、数值等表现却不像引用类型,暂时可以称为简单类型。而列表、元组、字典,包括以后学习的类和实例都可以认为是引用类型。你可以认为简单类型直接存在列表中,而引入类型只是把引用地址存在了列表中。
2.7 删除
2.7.1 remove() 方法–删除列表中的指定元素
remove() 方法从左至右查找第一个匹配 value 的值,找到就移除该元素,并返回 None,否则 ValueError。其语法格式如下:
In [25]: listname.remove?
Signature: listname.remove(value, /)
Docstring:
Remove first occurrence of value.
Raises ValueError if the value is not present.
Type: builtin_function_or_method
参数说明:
- listname:表示列表的名称。
- value:表示列表中要移除的值,这里只能进行精确匹配,即不能是元素值的一部分。
【示例1】删除列表中的指定元素。创建一个列表,然后应用列表对象的remove()方法删除列表中指定的元素,示例代码如下:
# 原列表
movie = [9, ('疯狂原始人', '功夫熊猫', 9), ['海底总动员', 9, '超能陆战队'], 9, '里约大冒险']
print('删除前的列表:', movie)
movie.remove(9) # 删除列表中的9
print('删除后的列表:', movie)
movie.remove(('疯狂原始人', '功夫熊猫', 9)) # 删除列表中的('疯狂原始人','功夫熊猫',9)
print('删除后的列表:', movie)
【示例2】删除数值列表中的指定数值。创建一个数值列表,然后应用列表对象的remove()方法删除列表中指定的数值元素,示例代码如下:
int_list = [1, 3, 5, 0, 4, 4, 1, 7, 9, 9, 6] # 模拟手机号码
print('删除前的列表:', int_list)
int_list.remove(1) # 删除数值元素1
print('删除后的列表:', int_list)
【示例3】通过for循环删除列表中指定类型的元素。创建一个包含多种类型元素的列表,然后循环遍历列表中的每个元素,如果元素类型为指定的元素类型,即可通过remove()方法删除当前元素即可。示例代码如下:
a_list = ['a', 123, 12.1, -1] # 创建多类型元素的列表
for i in a_list: # 循环遍历列表中的元素
if isinstance(i, str): # 判断元素的类型是否为字符类型
a_list.remove(i) # 是字符类型将当前元素在列表中移除
print('移除字符类型元素后的列表:', a_list) # 打印移除字符类型元素后的列表
【示例4】通过for循环删除列表中指定索引范围的元素。创建一个数值列表,循环遍历指定索引范围的列表对象,然后删除索引对应的元素值。示例代码如下:
number_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 数值列表
# 循环删除列表索引为0~5所对应的元素
for i in number_list[0:6]:
number_list.remove(i)
print('删除元素后的列表为:', number_list)
del 关键字、pop() 方法、remove() 方法的区别如下:
- del 关键字可以实现删除整个列表对象,而 pop() 方法与 remove() 方法无法实现。
- del 关键字与 pop() 方法在删除指定元素时需要通过指定元素索引,而 remove() 方法需要指定元素值对象。
- pop() 方法在删除元素时可以返回当前删除的元素值,而 del 关键字与 remove() 方法无法实现。
2.7.2 pop()方法–删除列表中的元素
在列表中,可以使用 pop() 方法删除列表中的一个元素(默认最后一个元素)。其语法格式如下:
In [27]: listname.pop?
Signature: listname.pop(index=-1, /)
Docstring:
Remove and return item at index (default last).
Raises IndexError if list is empty or index is out of range.
Type: builtin_function_or_method
参数说明:
- listname:表示列表的名称。
- index:列表中元素的索引值,必须是整数;如果不写,默认 index = -1。索引超界抛出 IndexError 错误
- 返回值:被删除的元素的值。
【示例1】删除列表中最后一个元素。定义一个保存8个元素的列表,删除最后一个元素,示例代码如下:
city = ['里约热内卢', '伦敦', '北京', '雅典', '悉尼', '亚特兰大', '巴塞罗那', '首尔'] # 原列表
delete = city.pop() # 删除列表的最后一个元素
print('删除的元素:', delete)
print('删除最后一个元素后的列表:', city)
【示例2】删除列表中指定元素。定义一个保存4个元素的列表,删除第2个元素,示例代码如下:
building = ['岳阳楼', '黄鹤楼', '鹳雀楼', '望湖楼'] # 原列表
delete = building.pop(1) # 删除列表的第2个元素,将删除的元素返回给delete
print('删除的元素:', delete)
print('删除第2个元素后的列表:', building)
说明:pop(index)括号中的index参数是可选的,index是列表中元素的索引值,pop(index)表示删除索引为index的元素,并将删除元素作为返回值。
【示例3】以负数作为索引删除列表元素。
building = ['岳阳楼', '黄鹤楼', '鹳雀楼', '望湖楼'] # 原列表
delete = building.pop(-4) # 删除列表的第1个元素,将删除的元素返回给delete
print('删除的元素:', delete)
print('删除第1个元素后的列表:', building)
2.7.3 clear() 方法–删除列表中的所有元素
使用 clear() 方法可以删除列表中的所有元素。其语法格式如下:
In [33]: listname.clear?
Signature: listname.clear() # listname:表示列表的名称
Docstring: Remove all items from list.
Type: builtin_function_or_method
【示例1】 清空列表中所有元素。
fish = ['鲸鱼', '鲨鱼', '刀鱼', '鲶鱼', '剑鱼', '章鱼', '鱿鱼', '鲤鱼'] # 原列表
print('清空前的列表:', fish)
fish.clear() # 清空列表中的所有元素
print('清空后的列表:', fish)
输出结果为:
清空前的列表: ['鲸鱼', '鲨鱼', '刀鱼', '鲶鱼', '剑鱼', '章鱼', '鱿鱼', '鲤鱼']
清空后的列表: []
【示例2】 清空二维列表中所有元素。创建一个二维列表,然后应用列表对象的clear()方法清空二维列表中的所有元素,示例代码如下:
# 定义二维列表
untitle = ['Python', 28, '人生苦短,我用Python', ['爬虫', '自动化运维', '云计算', 'Web开发']]
print('清空前的二维列表:', untitle)
untitle.clear() # 清空二维列表
print('清空后的二维列表:', untitle)
【示例3】 清空二维列表中的子列表。创建一个二维列表,然后通过列表索引的方式指定子列表的位置,再通过clear()方法清空子列表中的所有元素,示例代码如下:
untitle = ['Python', 28, '人生苦短,我用Python', ['爬虫', '自动化运维', '云计算', 'Web开发']]
print('清空前的二维列表:', untitle)
untitle[3].clear() # 清空子列表中的所有元素
# ['Python', 28, '人生苦短,我用Python', []]
print('清空后的二维列表:', untitle)
【示例4】 清空二维列表中与目标列表相同的子列表。循环遍历二维列表,比较子列表是否与目标列表相同,如果相同就将对应的子列表清空。代码如下:
two_lst = [[1, 2, 3], ['1', '2', '3'], [1, 2, 3]] # 二维列表
target_list = [1, 2, 3] # 目标列表
for i in two_lst:
if i == target_list: # 如果二维列表中子列表与目标列表相同
i.clear() # 清空二维列表中子列表
# [[], ['1', '2', '3'], []]
print('清空后的二维列表:', two_lst)
2.8 reverse() 方法–反转列表中的所有元素
列表对象提供了 reverse() 方法,使用该方法可以将列表中的所有元素进行反转。其语法格式如下:
In [37]: listname.reverse? # # listname:表示列表的名称
Signature: listname.reverse()
Docstring: Reverse *IN PLACE*.
Type: builtin_function_or_method
【示例1】符换列表中的所有元素反转。定义一个含有5个元素的列表,然后应用reverse()方法将原列表中的所有元素反转,示例代码如下:
num = ['一', '二', '三', '四', '五']
print('原列表:', num)
num.reverse() # 反转列表中的所有元素
print('新列表:', num)
【示例2】混合类型的列表中所有元素反转。对于混合类型的列表,也可以应用reverse()方法将原列表中的所有元素反转,示例代码如下:
num = [1, '二', ['Ⅲ', 4], (5, '⑥')]
print('原列表:', num)
num.reverse() # 反转列表中的所有元素
print('新列表:', num)
就地修改,这个方法最好不用,可以倒着读取,都不要反转。 示例:
num = [1, '二', ['Ⅲ', 4], (5, '⑥')]
for idx in range(len(num) - 1, -1, -1):
print(idx, num[idx])
for idx in range(-1, -len(num) - 1, -1):
print(idx, num[idx])
for idx in range(0, len(num)):
print(idx, num[-(idx + 1)])
2.9 sort() 方法–排序列表元素
列表对象中提供了 sort() 方法,该方法用于对原列表中的元素进行排序,排序后原列表中的元素顺序将发生改变。其语法格式如下:
In [38]: listname.sort?
Signature: listname.sort(*, key=None, reverse=False)
Docstring:
Sort the list in ascending order and return None.
The sort is in-place (i.e. the list itself is modified) and stable (i.e. the
order of two equal elements is maintained).
If a key function is given, apply it once to each list item and sort them,
ascending or descending, according to their function values.
The reverse flag can be set to sort in descending order.
Type: builtin_function_or_method
参数说明:
- listname:表示要进行排序的列表。
- key:表示指定一个从每个列表元素中提取一个用于比较的键(例如,设置
"key=str.lower"
表示在排序时不区分字母大小写)。 - reverse:可选参数,如果将其值指定为 True,则表示降序排列,如果为 False,则表示升序排列。默认为升序排列。
【示例1】数值列表的排序。定义一个保存10名学生Python理论成绩的列表,然后应用sort()方法对其进行排序,示例代码如下:
grade = [98, 99, 97, 100, 100, 96, 94, 89, 95, 100] # 10名学生Python理论成绩列表
print('原列表:', grade)
grade.sort() # 进行升序排列
print('升 序:', grade)
grade.sort(reverse=True) # 进行降序排列
print('降 序:', grade)
【示例2】字符串列表的排序。使用sort()方法对字符串列表进行排序时,采用的规则是先对大写字母排序,然后再对小写字母排序。如果想要对字符串列表进行排序(不区分大小写时),需要指定其key参数。例如,定义一个保存英文字符串的列表,然后应用sort()方法对其进行升序排列,示例代码如下:
char = ['cat', 'Tom', 'Angela', 'pet'] # 原列表
char.sort() # 默认区分字母大小写
print('区分字母大小写:', char)
char.sort(key=str.lower) # 不区分字母大小写
print('不区分字母大小写:', char)
【示例3】将列表按自定义规则排序。使用sort()方法也可以按指定的规则进行排序。具体方法是先定义排序规则的函数,然后调用sort()方法时,指定key参数值为自定义的函数名。例如,定义一个包含字典子元素的列表,实现按字典的指定键值进行排序,代码如下:
def rule_sort(elem): # 定义排序规则函数
return elem['english']
list1 = [{'name': 'mr', 'english': 99},
{'name': '碧海苍梧', 'english': 100},
{'name': '零语', 'english': 98}]
print('排序前:', list1)
list1.sort(key=rule_sort) # 按指定规则排序
print('升序排序后:', list1)
list1.sort(key=rule_sort, reverse=True) # 按指定规则排序
print('降序排序后:', list1)
【示例4】按拼音顺序对列表按中文排序。在Python中,对列表按中文排序,可以借助第三方模块xpinyin实现。例如,定义保存三国人物名称列表,并对其按拼音顺序排序,代码如下:
from xpinyin import Pinyin # 导入第三方模块,需要先应用pip install xpinyin命令安装
pin = Pinyin() # 实例化
result = [] # 临时列表
list1 = ['刘备', '曹操', '关羽', '诸葛亮', '张飞', '周瑜']
print('排序前:', list1)
for item in list1:
result.append((pin.get_pinyin(item), item)) # 添加拼音
result.sort() # 按拼音排序
result = [i[1] for i in result] # 去掉添加的拼音再生成列表
print('排序后:', result) # 输出排序后的结果
2.10 in 成员操作
在 Python 中,可以使用 in 关键字检查某个元素是否为序列的成员,即检查某个元素是否包含在某个序列中。语法格式如下:
value in sequence
其中,value 表示要检查的元素,sequence 表示指定的序列。示例:
print('a' in ['a', 'b', 'c'])
print([3, 4] in [1, 2, 3, [3, 4]])
运行上面的代码,将显示结果 True,表示在序列中存在指定的元素。另外,在 Python 中,也可以使用 not in 关键字实现检查某个元素是否不包含在指定的序列中。not in是 not 和 in 两个关键字的组合,主要用于判断特定的值在列表中不存在时返回 True,否则返回 False。其语法格式如下:
if 'A' not in listname:
参数说明:
'A'
表示需要在列表中查找的元素值。- listname 表示查找目标的列表名称。
- 返回值:在列表中未找到对应的元素将返回 True,否则返回 False。
示例:
In [39]: ls1 = ['A','B','C','D']
In [40]: 'A' not in ls1
Out[40]: False
In [41]: 'F' not in ls1
Out[41]: True
2.11 copy() 方法–复制列表中所有元素
在 Python 中,提供了 copy() 方法,使用该方法可以复制某一列表中的所有元素并生成一个新列表。其语法格式如下:
In [42]: listname.copy?
Signature: listname.copy() # # listname:表示列表的名称。shallow copy 浅拷贝
Docstring: Return a shallow copy of the list.
Type: builtin_function_or_method
# shadow copy: 影子拷贝,也叫浅拷贝。遇到引用类型数据,仅仅复制一个引用而已
# deep copy: 深拷贝,往往会递归复制一定深度
# 一般情况下,大多数语言提供的默认复制行为都是浅拷贝。
# Python内建数据类型,内部都实现了 == ,它的意思是内容比较
【示例1】将原列表中的所有元素复制到新列表中。定义一个保存影视类奖项名称的列表,然后应用copy()方法列表中的所有元素复制到新列表中,示例代码如下:
old = ['金鹰奖', '百花奖', '飞天奖', '白玉兰奖', '华表奖', '金鸡奖'] # 原列表
print('原列表:', old)
new = old.copy() # 将原列表的所有元素复制到新列表中
print('新列表:', new)
【示例2】混合类型的列表元素复制到新的列表当中。对于混合类型的列表,也可以应用copy()方法列表中的所有元素复制到新列表中,示例代码如下:
old = ['great', 54345, ['?', 68], (21, '加油'), '努力'] # 原列表
print('原列表:', old)
new = old.copy() # 将原列表的所有元素复制到新列表中
print('新列表:', new)
注意:copy()和直接赋值的区别:使用“=”直接赋值,是引用赋值,更改一个,另一个同样会变。copy()复制一个副本,原值和新复制的变量互不影响。如下面的例子所示:
a = ['龙虎英雄会', '十二金钱镖', '乱世枭雄', '老店风云', '三侠五义']
b = a # 直接赋值
c = a.copy() # 复制列表中的所有元素
print('a:', a)
print('b:', b)
print('c:', c, '\n')
del a[1] # 删除列表中的第2个元素
print('a:', a)
print('b:', b)
print('c:', c, '\n')
b.remove('老店风云') # 移除指定元素
print('a:', a)
print('b:', b)
print('c:', c, '\n')
c.append('禁烟风云') # 添加指定元素
print('a:', a)
print('b:', b)
print('c:', c)
其他示例:
import copy
a = list(range(4))
b = list(range(4))
print(a == b) # True
c = a # 引用
c[2] = 10
print(a) # [0,1,10,3]
print(a == b) # 还相等吗?False
print(a == c) # 相等吗 True
a = list(range(4))
b = a.copy()
print(a == b) # True
a[2] = 10
print(a == b) # False
a = [1, [2, 3, 4], 5]
b = a.copy()
print(a == b) # True
a[2] = 10
print(a == b) # False
a[2] = b[2]
print(a == b) # True
a[1][1] = 100
print(a == b) # 还相等吗?True
print(a) # [1,[2,100,4],5]
print(b) # [1,[2,100,4],5]
a = [1, [2, 3], 4]
b = copy.deepcopy(a)
print(a == b) # True
a[1][1] = 100
print(a == b) # 还相等吗?False
print(a) # [1, [2, 100], 4]
print(b) # [1, [2, 3], 4]
参考文章学习:https://blog.csdn.net/xw1680/article/details/134547412
2.12 遍历列表
遍历列表中的所有元素是常用的一种操作,在遍历的过程中可以完成查询、处理等功能。在生活中,如果想要去商场买一件衣服,就需要在商场中逛一遍,看是否有想要的衣服,逛商场的过程就相当于列表的遍历操作。在 Python 中遍历列表的方法有多种,下面介绍两种常用的方法。
2.12.1 直接使用for循环实现
直接使用 for 循环遍历列表,只能输出元素的值,语法格式如下:
for item in list_name:
print(item)
其中,item 用于保存获取到的元素值,要输出元素内容时,直接输出该变量即可;list_name 为列表名称。例如,定义一个保存 2019~2020 赛季 NBA 常规赛西部前八排名预测的列表,然后通过 for 循环遍历该列表,并输出各个球队的名称,代码如下:
print("2019~2020赛季NBA常规赛西部前八排名预测: ")
team_list = ["洛杉矶湖人", "洛杉矶快船", "丹佛掘金", "犹他爵士",
"404队", "俄克拉荷马雷霆", "达拉斯独行侠", "新奥尔良鹈鹕"]
for item in team_list:
print(item)
2.12.2 使用for循环和enumerate()函数实现
enumerate() 函数将一个可迭代的对象组合为一个带有数据和数据下标的索引序列,返回一个枚举对象,enumerate() 函数多用在 for 循环中,用于遍历序列中的元素以及它们的下标。其语法格式如下:
In [43]: enumerate?
Init signature: enumerate(iterable, start=0)
Docstring:
Return an enumerate object.
iterable
an object supporting iteration
The enumerate object yields pairs containing a count (from start, which
defaults to zero) and a value yielded by the iterable argument.
enumerate is useful for obtaining an indexed list:
(0, seq[0]), (1, seq[1]), (2, seq[2]), ...
Type: type
Subclasses:
参数说明:
- iterable:一个序列、迭代器或其他支持迭代的对象,如列表、元组、字符串等。
- start:下标的起始值,默认从0开始。
- 返回值:返回一个 enumerate (枚举)对象。
【示例1】遍历enumerate对象。enumerate()函数是将一个可迭代的对象组合为一个带有数据和数据的索引序列,返回一个枚举对象。例如,定义一个保存中国古典文学中四大名著的列表,然后通过for循环和enumerate()函数遍历该列表,并输出索引和四大名著的名称,示例代码如下:
print('中国古典文学中四大名著:')
team = ['《三国演义》', '《水浒传》', '《西游记》', '《红楼梦》']
for index, item in enumerate(team): # 遍历索引与四大名著的名称
print(index + 1, item) # 打印索引与四大名著的名称
【示例2】将enumerate对象转换为列表。定义一个元组,使用enumerate()函数根据定义的元组创建一个enumerate对象,并使用list()函数将其转换为列表,示例代码如下:
num = ('one', 'two', 'three', 'four') # 创建元组数据
print(enumerate(num)) # 返回一个enumerate对象
print(list(enumerate(num))) # 使用list()函数转换为列表,下标的起始值默认从0开始
print(list(enumerate(num, 2))) # 设置下标的起始值从2开始
提示:从上面的运行结果可以看出,enumerate()函数返回的是一个enumerate对象,如果想要得到列表,可以用list()函数进行转换。
【示例3】通过enumerate()函数合并列表索引。定义两个列表,通过enumerate()函数将其组成索引序列,最后合成一个列表,并且实现下标的连续性。示例代码如下:
list1 = ['python', 'java', 'asp.net', 'c++', 'vb'] # 创建列表list1
list2 = ['sqlserver', 'oracle', 'mysql', 'mongodb'] # 创建列表list2
en1 = enumerate(list1) # 创建list1列表的enumerate对象
en2 = enumerate(list2, start=5) # 创建list2列表的enumerate对象,下标以5开始
resultList = list(en1) + list(en2) # 将两个enumerate对象转换为列表,并合为一个列表
print('合并后的列表内容为:\n', resultList) # 打印合并后的列表内容
【示例4】循环遍历序列中的元素及下标。enumerate()函数多用在for循环中,用于遍历序列中的元素以及它们的下标。使用for循环和enumerate()函数实现同时输出索引值和元素内容的功能,其语法格式如下:
for index,item in enumerate(listname):
# 输出index和item
参数说明:
- index:用于保存元素的索引。
- item:用于保存获取到的元素值,要输出元素内容时,直接输出该变量即可。
- listname:序列名称。
通过 enumerate() 函数,循环遍历序列中的元素及下标。示例代码如下:
list3 = ['Forever', 'I Need You', 'Alone', 'Hello'] # 列表数据
for index, item in enumerate(list3): # 循环遍历列表中的元素及下标
print('列表元素下标为:', index, '列表元素为:', item)
输出结果为:
列表元素下标为: 0 列表元素为: Forever
列表元素下标为: 1 列表元素为: I Need You
列表元素下标为: 2 列表元素为: Alone
列表元素下标为: 3 列表元素为: Hello
2.13 列表推导式
使用列表推导式可以快速生成一个列表,或者根据某个列表生成满足指定需求的列表。列表推导式通常有以下几种常用的语法格式。
2.13.1 生成指定范围的数值列表
语法格式如下:
listname = [Expression for var in range]
参数说明:
- listname:表示生成的列表名称。
- Expression:表达式,用于计算新列表的元素。
- var:循环变量。
- range:采用 range() 函数生成的 range 对象。
例如,要生成一个包括10个随机数的列表,要求数的范围在10~100(包括)之间,具体代码如下:
import random # 导入random标准库
num_list = [random.randint(10, 100) for i in range(10)]
print("生成的随机数为:", num_list)
2.13.2 根据列表生成指定需求的列表
语法格式如下:
newlist = [Expression for var in listname]
参数说明:
- newlist:表示新生成的列表名称。
- Expression:表达式,用于计算新列表的元素。
- var:变量,值为后面列表的每个元素值。
- listname:用于生成新列表的原列表。
例如,定义一个记录商品价格的列表,然后应用列表推导式生成一个将全部商品价格打五折的列表,具体代码如下:
price = [1200, 5330, 2988, 6200, 1998, 8888]
sale = [int(x * 0.5) for x in price]
print("原价格: ", price)
print("打五折的价格: ", sale)
2.13.3 从列表中选择符合条件的元素组成新的列表
语法格式如下:
newlist = [Expression for var in listname if condition]
参数说明:
- newlist:表示新生成的列表名称。
- Expression:表达式,用于计算新列表的元素。
- var:变量,值为后面列表的每个元素值。
- listname:用于生成新列表的原列表。
- condition:条件表达式,用于指定筛选条件
例如,定义一个记录商品价格的列表,然后应用列表推导式生成一个商品价格高于5000元的列表,具体代码如下:
price = [1200, 5330, 2988, 6200, 1998, 8888]
sale = [x for x in price if x > 5000]
print("原列表: ", price)
print("价格高于5000的: ", sale)
2.14 二维列表的使用
在 Python 中,由于列表元素还可以是列表,所以它也支持二维列表的概念。那么什么是二维列表?酒店有很多房间,这些房间都可以构成一个列表,如果这个酒店有500个房间,那么拿到499号房钥匙的旅客可能就不高兴了,从1号房走到499号房要花好长时间,因此酒店设置了很多楼层,每一个楼层都会有很多房间,形成一个立体的结构,把大量的房间均摊到每个楼层,这种结构就是二维列表结构。使用二维列表结构表示酒店每个楼层的房间号的效果如下图所示:
二维列表中的信息以行和列的形式表示,第一个下标代表元素所在的行,第二个下标代表元素所在的列。在 Python 中,创建二维列表有以下三种常用的方法。
2.14.1 直接定义二维列表
在 Python 中,二维列表是包含列表的列表,即一个列表的每一个元素又都是一个列表。例如,下面就是一个二维列表:
[['千', '山', '鸟', '飞', '绝'],
['万', '径', '人', '踪', '灭'],
['孤', '舟', '蓑', '笠', '翁'],
['独', '钓', '寒', '江', '雪']]
在创建二维列表时,可以直接使用下面的语法格式进行定义:
list_name = [[元素11, 元素12, 元素13, …, 元素1n],
[元素21, 元素22, 元素23, …, 元素2n],
…,
[元素n1, 元素n2, 元素n3, …, 元素nn]]
参数说明:
- list_name:表示生成的列表名称。
[元素11, 元素12, 元素13, …, 元素1n]
:表示二维列表的第一行,也是一个列表。其中"元素11,元素12,…元素1n"
代表第一行中的列。[元素21, 元素22, 元素23, …, 元素2n]
:表示二维列表的第二行。[元素n1, 元素n2, 元素n3, …, 元素nn]
:表示二维列表的第n行。
例如,定义一个包含4行5列的二维列表,可以使用下面的代码:
verse_list = [['千', '山', '鸟', '飞', '绝'], ['万', '径', '人', '踪', '灭'],
['孤', '舟', '蓑', '笠', '翁'], ['独', '钓', '寒', '江', '雪']]
print(verse_list)
2.14.2 使用嵌套的for循环创建
创建二维列表,可以使用嵌套的for循环实现。例如,创建一个包含4行5列的二维列表,可以使用下面的代码:
arr = [] # 创建一个空列表
for i in range(4):
arr.append([]) # 在空列表中再添加一个空列表
for j in range(5):
arr[i].append(j) # 为内层列表添加元素
print(arr)
2.14.3 使用列表推导式创建
使用列表推导式也可以创建二维列表,因为这种方法比较简洁,所以建议使用这种方法创建二维列表。例如,使用列表推导式创建一个包含4行5列的二维列表可以使用下面的代码:
arr = [[j for j in range(5)] for i in range(4)]
创建二维数组后,可以通过以下语法格式访问列表中的元素:
list_name[下标1][下标2]
参数说明:
- list_name:列表名称。
- 下标1:表示列表中第几行,下标值从0开始,即第一行的下标为0。
- 下标2:表示列表中第几列,下标值从0开始,即第一列的下标为0。
例如,要访问二维列表中的第2行,第4列,可以使用下面的代码:
verse_list[1][3]
在 PyCharm 中创建一个名称为 print_verse.py 的文件,然后在该文件中首先定义4个字符串,内容为柳宗元的《江雪》中的诗句,并定义一个二维列表,然后应用嵌套的 for 循环将古诗以横版方式输出,再将二维列表进行逆序排列,最后应用嵌套的 for 循环将古诗以竖版方式输出,代码如下:
str1 = "千山鸟飞绝"
str2 = "万径人踪灭"
str3 = "孤舟蓑笠翁"
str4 = "独钓寒江雪"
verse = [list(str1), list(str2), list(str3), list(str4)] # 定义一个二维列表
print("\n-- 横版 --\n")
for i in range(4): # 循环古诗的每一行
for j in range(5): # 循环每一行的每个字(列)
if j == 4: # 如果是一行中的最后一个字
print(verse[i][j]) # 换行输出
else:
print(verse[i][j], end="") # 不换行输出
verse.reverse() # 对列表进行逆序排列
print("\n-- 竖版 --\n")
for i in range(5): # 循环每一行的每个字(列)
for j in range(4): # 循环新逆序排列后的第一行
if j == 3: # 如果是最后一行
print(verse[j][i]) # 换行输出
else:
print(verse[j][i], end="") # 不换行输出
说明:在上面的代码中,list() 函数用于将字符串转换为列表;列表对象的 reverse() 方法用于对列表进行逆序排列,即将列表的最后一个元素移到第一个,倒数第二个元素移到第二个,以此类推。