更深层次理解Python的 列表元组字典集合(工作面试学习必需掌握的知识点)
Posted 无限嚣张(菜菜)
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了更深层次理解Python的 列表元组字典集合(工作面试学习必需掌握的知识点)相关的知识,希望对你有一定的参考价值。
目录
序列介绍
字符串、列表、元组、集合都是序列,序列是什么呢?序列是一种数据存储方式,用来存储一系列的数据。在内存中,序列就是一块用来存放多个值的连续的内存空间。比如说一个整数序列,[10,20,30,40],可以这样表示:
如下图理解,我们将 10、20、30、40每一个对象的地址分别存储到列表的内存,最后将整个列表的地址赋给变量a。也就是我们先通过变量a找到列表的地址,再通过索引找到列表元素的地址,再通过列表元素的地址找到对象。
在序列中,存储的是对象的地址,而不是对象的值,上一篇博客我们着重对字符串进行介绍,接下来,我们将对列表、元组、集合进行介绍。
列表
列表可以用来存储任意数目、任意类型的数据集合,列表是内置可变序列,是包含多个元素的有序连续的内存空间。列表定义的标准语法格式如下:
a = [10,20,30,40]
其中10,20,30,40这些称为列表a的元素。而列表中的元素不要求类型相同,可以类型不同,比如:
a = [10,20,‘yyq’,True]
里边既可以有数字、也可以有字符串、还可以有布尔型。
列表的创建
基本语法[]创建
list = [1,2,'3',True,2,3];
print(list)
list()创建
使用list()可以将任何迭代的数据转化成列表。
a = list()
print(a)
b = list(range(10))
print(b)
# 将字符串转化为列表
c = list('I Love you yyq')
print(c)
range()创建整数列表
range()可以帮助我们非常方便的创建整数列表,这在开发中非常重要,语法格式如下:
range([start,end,step])
start参数:可选,表示起始数字,默认是0;
end参数:可选,表示结尾数字;
step参数:可选,表示步长,默认是1.
在Python3中range()返回的是一个range对象,而不是列表,我们需要通过list()方法将其转化成列表对象。
# range 产生的是整数
a = list(range(2,10,3))
print(a)
b = list(range(-8,20,2))
print(b)
如果倒序怎么办?我们将步长换成负数即可。
推导式生成列表
使用列表推导式,可以非常方便的创建列表,在开发中经常使用。他一般和控制语句结合使用。
a = [x*3 for x in range(8)]
print(a)
b = [x*3 for x in range(8) if x%2==0]
print(b)
列表对象常用方法汇总
序号 | 方法 | 要点 | 描述 |
1 | list.append(x) | 增加元素 | 将元素x增加到列表的尾部 |
2 | list.extend(alist) | 增加元素 | 将列表alist的所有元素增加到列表尾部 |
3 | list.insert(index,x) | 增加元素 | 在列表list,指定位置index插入元素x |
4 | list.remove(x) | 删除元素 | 在列表list删除首次出现的指定元素x |
5 | list.pop([index]) | 删除元素 | 删除并返回列表list指定位置index处的元素,默认是最后一个元素,索引是从0开始的 |
6 | list.clear() | 删除所有元素 | 删除列表所有元素,并不是列表对象,此时对象的地址还存在 |
7 | list.index(x) | 访问元素 | 返回第一个x索引位置,若不存在x元素抛出异常 |
8 | list.count(x) | 计数 | 返回指定元素x在列表list出现的次数 |
9 | len(list) | 列表长度 | 返回列表中包含元素的个数 |
10 | list.reverse() | 翻转列表 | 所有元素原地翻转 |
11 | list.sort() | 排序 | 所有元素原地排序 |
12 | list.copy | 浅拷贝 | 所有列表对象的浅拷贝 |
示例说明:
1.将元素插入列表尾部
当列表增加和删除元素时,列表会自动进行内存管理,大大减少程序员的负担。但这个特点涉及列表元素的大量移动,效率低下,除非必要,否则我们只在列表尾部进行添加元素或者删除元素,这会大大提高列表的操作效率。而+运算符操作,并不是真正尾部添加元素,而是创建新的列表对象,将原列表元素和新列表元素依次复制到新的列表中,对于操作大量元素,不建议使用。
k = [1,2,'3',True];
# 将'yyq'增加到列表的尾部
k.append('yyq')
c = k+['yyq']
print(k,c)
print(id(k),id(c))
2.将列表alist的所有元素插入列表list之后,在原地拼接,不涉及新的对象的创建。
list = [1,2,'3',True];
alist = ['I','','','Love','','You','','yyq']
# 将列表alist 的所有元素插入到list 列表之后
list.extend(alist)
print(list)
3.将列表list指定位置插入元素
使用insert()方法可以将指定的元素插入到列表对象的任意位置。这样会让插入位置后面所有的元素进行移动,会影响处理速度。涉及大量元素时,尽量避免使用,类似发生这种移动函数的还有:remove()、pop()、del(),他们在删除非尾部元素时也会发生操作位置后面元素的移动,也涉及到数组的移动与拷贝。
list = [1,2,'3',True];
# 将列表list指定位置插入元素
list.insert(2,False)
print(list)
4.在列表list删除首次出现的指定元素x
list = [1,2,'3',True,2];
# 在列表list删除首次出现的指定元素x
list.remove(2)
print(list)
5.删除并返回列表list指定位置index处的元素,或者del list[2],默认是最后一个元素,索引是从0开始的.看似是元素的删除,实际里边涉及到数组的移动和拷贝。将字符’3’删除以后,将索引3位置移动到索引2位置,将索引4位置移动到索引3的位置。别的列表中间操作,同理。
list = [1,2,'3',True,2];
# 删除并返回列表list指定位置index处的元素
list.pop(2)
print(list)
6.删除列表所有元素,并不是列表对象,此时对象的地址还存在
list = [1,2,'3',True,2];
list.clear()
print(list)
print(id(list))
7.返回第一个x索引位置,若不存在x元素抛出异常
list = [1,2,'3',True,2];
a = list.index(2)
print(a)
8.返回指定元素x在列表list出现的次数
list = [1,2,'3',True,2];
a = list.count(2)
print(a)
9. 返回列表中包含元素的个数
list = [1,2,'3',True,2];
a = len(list)
print(a)
10.所有元素原地翻转,也就是前后顺序颠倒
list = [1,2,'3',True,2];
list.reverse()
print(list)
11.所有元素原地排序,必须都是数字,不需要创建新列表排序,列表中不能是字符串。
list = [1,2,5,6,100,0.1,6,2];
list.sort()
print(list)
注意:如果是降序排序,则为a.sort(reverse=True),我们也可以通过内置函数sorted()进行排序,这个方法是返回新的列表,不对原列表做修改。
12. 所有列表对象的浅拷贝
list = [1,2,'3',True,2,3];
list.copy()
print(list)
13.列表的乘法扩展
使用乘法扩展列表,生成一个新列表时,对原列表进行多次操作。
a = ['I',520]
b = a*3;
print(b)
根据上述示例可知:Python的列表大小可变,根据实际需要,可以调整列表的大小,字符串和列表都是序列类型,一个字符串是一个序列,一个列表是任何元素的序列,我上一篇博客https://blog.csdn.net/zywcxz/article/details/128317597详细介绍了字符串的应用详解,在列表中的应用几乎一模一样,有需要的小伙伴看一下。
列表元素的访问和计数
通过索引直接访问元素
我们可以通过索引直接访问元素,索引的区间是[0,len(list)-1]这个范围,超出这个范围将会抛出异常。
a = list(x for x in range(10) if x % 3 == 0)
b = len(a)
m = input('请输入整数类型:')
if int(m) > (b-1):
print('输出超出索引维度')
else:
c = a[int(m)]
print(a, b, c)
成员资格判断
判断列表中是否存在指定元素,我们可以用count()方法,返回0则表示不存在,返回大于0表示存在。但是,一般我们会使用更加简洁的in关键字来判断。直接返回True和False。
a = list(x for x in range(10) if x % 3 == 0 )
20 in a
切片操作
切片是Python 序列及其重要的操作,适用于列表,元祖,字符串等等,按照索引查找。切片格式如下:
[起始偏移量start:终止偏移量:步长step]
b = list(n for n in range(100) if n%30 ==0)
# 提取所有字符
c = b[::]
#从开始到结尾
d = b[2::]
#从开始到end-1
e = b[0:3:]
#从开始到结尾,步长为2
f = b[0:3:2]
print(b)
print(c)
print(d)
print(e)
print(f)
切片操作时,起始偏移和终止偏移量不在[0,字符串长度-1]这个范围,也不会报错。其实偏移量小于0则会当做0,终止偏移量大于len(list)-1,则会被当成len(list)-1,eg:
a = list(range(0,100,10))
print(a)
a[1:100]
列表遍历
格式如下:
for obj in list(Obj)
print(obj)
eg:
g = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
for x in g:
print(x)
列表相关的其他内置函数汇总
1.max 和 min
用于返回列表中的最大值和最小值
a = list(x for x in range(100) if x % 10 == 0)
b = min(a)
c = max(a)
print(a,b,c)
2.sum
对数值型列表的所有元素求和,对非数值型列表,会报错
a = list(x for x in range(100) if x % 10 == 0)
b = sum(a)
print(b)
多维列表
二维列表
一维列表可以帮助我们存储一维,线性的数据,二维列表可以帮助我们存储二维,表格的数据。
姓名 | 语文成绩 | 数学成绩 | 英语成绩 |
张三 | 90 | 60 | 90 |
王五 | 80 | 90 | 80 |
李四 | 85 | 100 | 60 |
内存结构图如下:我们通过找到二维列表对象的索引找到里边的列表对象,再通过里边的列表对象索引找到最里边的元素,对其进行操作。
a=[
['张三',90,60,90],
['王五',80,90,80],
['李四',85,100,60],
]
for m in range(3): # 行操作
for n in range(4): # 列操作
print(a[m][n],end='\\t')
print()# 打印完换行
元组tuple
列表属于可变序列,可以任意修改列表中的元素,元组属于不可变序列,不能改变元组中的元素。因此元组没有增加元素、删除元素的相关方法。因此只需要学习元组的创建和删除,元组元素的访问计数即可。元组支持如下操作:1、索引访问 2、切片操作 3、连接操作 4、成员关系操作 5、比较运算操作 6、计数:元组长度len()、最大值max()、最小值min()、求和sum()等。
元组的创建
1.通过()创建元组,小括号可以省略
如果元组只有一个元素,则必须后面加逗号,这是因为解释器会把(1)解释为整数,而1,(1,)则解释我将会解释为元组。
c = (10,20,30)
d = 10,10,30
print(type(c),type(d))
2.通过tuple()创建元组
tuple(可迭代的对象)
eg:
b = tuple() # 创建一个空元组对象
c = tuple("abc")
d = tuple(range(3))
e = tuple([2,3,4])
f = tuple(['1',2,3]) # 将列表转化为元组
print(b,c,d,e,f)
总结:tuple() 可以接收列表、字符串、其他序列类型,迭代器等生成元组。
list()可以接收元组、字符串、其他序列类型、迭代器等生成列表。
元组的元素访问和计数
1.元组的元素不能修改
2.元组的元素访问和列表一样,只不过返回的仍然是元组
3.列表关于排序的方法list.sorted()是修改原列表对象,元组没有该方法,如果要对元组排序,只能使用内置函数sqrted(tupleObj),并生成新的列表对象。sorted生成的都是列表,不管你传的是列表还是元组。
ZIP
zip(列表1,列表2,...)将多个列表对应位置的元素组合为元组,并返回这个zip对象。
a = [10,20,30]
b = [40,50,60]
c = [70,80,90]
d = zip(a,b,c)
print(list(d))
生成器推导式创建元组
从形式上看,生成器推导式与列表推导式类似,只是生成器推导式使用小括号,列表推导式生成列表对象,生成器推导式生成的不是列表也不是元组,而是一个生成器对象。我们可以通过生成器对象,转化成列表或者元组。也可以使用生成器对象的_next_()方法进行遍历,或者直接作为迭代器对象来使用。不管什么方式使用,元素访问结束后,如果需要重新访问其中的元素,必须重新创建该生成器对象,只能用一次。
s = (x*2 for x in range(5))
print(tuple(s))
print(tuple(s))
用s.__next__()指针来移动操作,根据序列去取值,指针以此后移
s = (x*2 for x in range(5))
print(s.__next__())
print(s.__next__())
print(s.__next__())
print(s.__next__())
print(s.__next__())
字典
字典是"键值对"的无序可变序列,键值对是成对存储的。通过对来操作值。来字典中每一个元素都是一个“键值对”,包含:"键对象”和值对象。可以通过“键对象”实现快速获取、删除、更新对象的“值对象”。
列表中我们通过“下标数字”找到对象。字典中通过“键对象”找到对应的值对象。“键”是任意的不可变数据,比如:整数、浮点数、字符串、元组。但是,列表、字典、集合这些可变对象,不能作为“键”。并且键不可重复。“值”可以是任意的数据,并且“键不可重复”。
字典的定义方式:
a = 'name':'gaoqi','age':18,'job':'programmer'
其中有三个键值对,'name'、'age'、'job'是键,'gaoqi','18','programmer'是对.
其中我们传入 'name'这个键就可以找到'gaoqi'这个对。利用a.get(‘name’),我感觉和C语言结构体类似。
字典的创建
1.(1)我们可以通过(2)dict()来创建字典对象
(1)通过
a = 'name':'gaoqi','age':18,'job':'programmer'
a.get('name')
(2)dict()来创建字典对象
①注意,键不加字符号,且用的‘=’而不是冒号,注意区别
b = dict(姓名='小花',年龄=18,工作='村花')
print(b)
②把键值和对放在一块,并且用[]表示,注意是,而不是:
b = dict([('姓名','小花'),('年龄',18),('工作','村花')])
print(b)
2.通过zip()创建字典对象
k = ['姓名','年龄','工作']
v = ['小花',18,'村花']
m = dict(zip(k,v))
print(m)
3.通过fromkeys创建值为空的字典,只有键没有值
a = dict.fromkeys(['姓名','年龄','工作'])
print(a)
字典元素的访问
1.通过键获得“值”,若键不存在,则抛出异常。
k = ['姓名','年龄','工作']
v = ['小花',18,'村花']
m = dict(zip(k,v))
print(m)
m['姓名']
2.通过get()方法获得值,推荐使用。有点是:指定键不存在,返回None;也可以设定指定键不存在默认返回的对象。推荐使用get()获取值对象。
k = ['姓名','年龄','工作']
v = ['小花',18,'村花']
m = dict(zip(k,v))
print(m)
m.get('年龄')
3.列出所有的键值对,进行遍历,是一个列表,里边包含元组
4.列出所有的键a.keys(),列出所有的值a.value()
5.键值对的个数用len()函数查看
6.检测一个“键”是否在字典中,用 in
字典元素添加、修改删除
1.给字典新增“键值对”。如果“键已经存在”,则覆盖就得键值对;如果“键不存在”,则新增“键值对”。
k = ['姓名','年龄','工作']
v = ['小花',18,'村花']
m = dict(zip(k,v))
print(m)
m['地址']='女儿国'
print(m)
2.使用update()将新字典中所有键值对全部添加到旧字典对象,如果key有重复直接覆盖。
3.字典元素中的删除,可以使用del方法;或者clear()删除所有的建值对;pop删除指定的键值对,并返回对应的‘值对象’。
k = ['姓名','年龄','工作']
v = ['小花',18,'村花']
m = dict(zip(k,v))
o = ['姓名','属相','生日']
p = ['小花','兔','5.21']
r = dict(zip(o,p))
print(m)
del(m['姓名'])
b = r.pop('属相')
print(m)
print(b)
4.popitem():随机删除和返回该键值对。字典是“无序可变序列”,因此没有第一个元素,最后一个元素的概念;popitem弹出随机项,因为字典并没有“最后元素”或者其他顺序的概念。若想一个接一个地移除,这个方法是非常有效的(因为不用首先获取键的列表)。
k = ['姓名','年龄','工作']
v = ['小花',18,'村花']
m = dict(zip(k,v))
o = ['姓名','属相','生日']
p = ['小花','兔','5.21']
r = dict(zip(o,p))
print(m)
m.popitem()
m.popitem()
m.popitem()
序列解包
序列解包可以用于元组、列表、字典。序列解包可以让我们方便的对多个变量赋值。
x,y,z = (20,30,10)
(x,y,z) = (20,30,10)
[a,b,c] = [10,20,30]
序列解包用于字典时,默认是对“键”进行操作;如果需要对键值对操作,则需要使用items(),如果需要对“值”进行操作,则需要使用values();方便对多个变量赋值。时
k = ['姓名','年龄','工作']
v = ['小花',18,'村花']
m = dict(zip(k,v))
o = ['姓名','属相','生日']
p = ['小花','兔','5.21']
r = dict(zip(o,p))
print(m)
a,b,c = m #默认对键进行操作
print(a,b,c)
a,b,c = m.items() #对键值对进行操作
print(a,b,c)
a,b,c = m.values() #对值进行操作
print(a,b,c)
表格数据使用字典和列表存储,并实现访问
在我们今后的学习中, 格
姓名 | 语文成绩 | 数学成绩 | 英语成绩 |
张三 | 90 | 60 | 90 |
王五 | 80 | 90 | 80 |
李四 | 85 | 100 | 60 |
a1 = '姓名': '张三', '语文成绩': 90, '数学成绩': '60', '英语成绩': '90'
a2 = '姓名': '王五', '语文成绩': 80, '数学成绩': '90', '英语成绩': '80'
a3 = '姓名': '李四', '语文成绩': 85, '数学成绩': '100', '英语成绩': '60'
tb = [a1, a2, a3]
# 获得语文成绩
for i in range(len(tb)):
print(tb[i].get('语文成绩'))
字典核心底层原理(非常重要)
字典对象的核心是散列表。散列表是一个稀疏数据(总是有空白元素的数组),数组的每个单元叫做bucket.每个bucket有两部分:一个是键对象的引用,一个是值对象的引用。由于,所有bucket结构和大小一致,我们通过偏移量来读取指定bucket.
理解:key既可以数值也可以字符串,怎么把一个key值对应成一个索引值?分两个步骤:
①将一个键值对放进字典的底层过程
a =
a["name"] = "yyq"
print(a)
假设字典a对象创建完后,数组长度为8,我们如何把它变成0-7的数字索引,最后将他放进去呢?我们要把“name”=“yyq”这个键值对放进字典对象a中,首先第一步需要计算键“name”的散列值。Python中通过hash()来计算。
a =
a["name"] = "yyq"
print(bin(hash("name")))
print(a)
由于数组长度为8,我们可以拿计算出的散列值的最右边3位数字作为偏移量,即“101”,十进制是数字5。我们查看偏移量5,对应的bucket是否为空。如果为空,则将键值对放不进去。如果不为空,则依次取右边3位作为偏移量,即 "100",十进制是数字。如果都满了,数组将扩容。
再查看偏移量为4的bucket是否为空。直到找到为空的bucket将键值对放进去,流程图如下:
②根据键查找“键值对”的底层过程
和存储的底层流程算法一致,也是依次取散列值的不同位置的数字,假设数组长度为8,我们可以拿计算出的散列值的最右边3位数字作为偏移量,即“101”,十进制是数字5。我们查看偏移量5,对应的bucket是否为空。如果为空,则返回None。如果不为空,则将这个bucket的键对象计算对应的散列值,和我们的散列值进行比较,如果相等。则将对应的”值对象”返回。如果不相等,则依次取其他几位数字,重新计算偏移量。重新取完后仍然没有找到,则返回None,流程图如下:
字典用法总结:
1.键必须可散列
(1)数字、字符串、元组都是可散列。
(2)自定义对象需要支持下面三点:
①支持hash()函数
②支持通过_eq_()方法检测相等性
③若a == b为真,则has(a)==has(b)也为真
2.字典在内存中开销巨大,典型中的空间换时间。
3.键查询速度很快。
4.往字典里面添加新建可能导致扩容,导致散列表中键的次序变化。因此,不要在遍历字典的同时进行字典的修改。
集合
集合是无序可变,元素不能重复。实际上,集合底层是字典的实现,集合的所有元素都是字典中的“键对象”,因此不能重复的且唯一的。
集合的创建和删除
1.使用创建集合对象,并使用add()方法添加元素
a = 1,2,3
a.add(4)
print(a)
2.使用set(),将列表、元组等可迭代对象转成集合。如果原来数据存在重复数据,则只保留一个。
b = ['a','x','c']
set(b)
print(b)
3.remove()删除指定元素;clear()清空整个集合。
c = ['a','x','c']
c.remove('a')
c.clear()
print(c)
集合相关操作
像数学中概念一样,Python对集合也提供了并集、交集、差集等运算,示例如下:
a = 1,3,'sxt'
b = 'he','it','sxt'
c = a|b # 并集
d = a-b # 差集
e = a&b # 交集
f = a.union(b) # 并集
g = a.difference(b) # 差集
h = a.intersection(b) # 交集
print(c,d,e,end = '\\t')
print(f,g,h,end = '\\t')
总结(列表、元组、字典、集合区别)
1.列表与元组、字典、集合的区别
①列表与元组区别:列表内的值是可以修改的,元组不能修改;列表是可变类型而元组是不可变类型
②列表与字典区别:列表存储值,而字典存储键值对;列表是有序序列而字典是无序序列
③列表与集合区别: 列表是有序序列,集合是无序序列;列表内可以存储重复数据,集合内不能存储重复数据
2.元组与字典、集合的区别
①元组与字典区别:元组是不可变类型,字典式可变类型;元组是有序序列,字典是无序序列;元组值不可以更改,字典的值是可以更改的;
②元组与集合区别:元组是不可变类型,集合是可变类型,元组是有序序列,集合是无序序列;元组存储的值可以重复,集合存储的值不能重复
3.字典与集合区别
字典与集合区别:字典存储的值可重复,集合存储的值是不可重复;
以上是关于更深层次理解Python的 列表元组字典集合(工作面试学习必需掌握的知识点)的主要内容,如果未能解决你的问题,请参考以下文章