5.1简介
在计算机程序中会有很多数据,这些数据也需要一个容器将他们管理起来,这就是数据结构。常见的数据结构:数组(Array)、集合(Set)、列表(List)、队列(Queue)、链表(Linkedlist)、树(Tree)、堆(Heap)、栈(Stack)和字典(Dictionary)等结构。
Python中数据容器主要有:序列、集合和字典。
注:Python中并没有数组结构,因为数组要求元素类型是一致的。而Python作为动态类型语言,不强制声明变量的数据类型,也不能强制检查元素的数据类型。所以Python中没有数组结构
5.2序列
序列(sequence)是一种可迭代的,元素是有序的,可以重复出现的数据结构。序列可以通过索引访问元素。
序列包括的结构有:列表(list)、字符串(str)、元组(tuple)、范围(range)、和字节序列(bytes)。序列可进行的操作有:索引、分片、加和乘。
5.2.1序列操作
5.2.1.1索引操作
序列中第一个元素的索引是0,其他元素的索引是第一个元素的偏移量。可以有正偏移量,称为正值索引;也可以有负偏移量,称为负值索引。正值索引最后一个元素索引是“序列长度-1”,负值索引最后一个元素索引是“-1”
注:关于负索引略有不同
s = 'Genius'
print('长度为'+str(len(s)))
print(type(s[0]))
print(s[0])
print(s[-1])
print(max(s)) #最后一个值
print(min(s)) #第一个值
#输出
长度为6
<class 'str'>
G
s
u
G
[Finished in 0.2s]
5.2.1.2序列的加和乘
前面介绍过了,不说了
5.2.1.3序列分片
序列的分片(Slicing)就是从序列中切分出小的子序列。分片使用分片运算符,分片运算符有两种形式:
- [start:end]。start是开始索引,end是结束索引。
- [start:end:step]。start是开始索引,end是结束索引,step是步长,步长是在分片时获取元素的间隔。步长可以为正整数,也可为负整数。
注:切下的分片包括start位置元素,但不包括end位置元素,start和end都可以省略。
s = 'Genius'
print('长度为'+str(len(s)))
print(s[0:6]) #s索引为0-5 即为[start,end)
print(s[:6])
print(s[0:-1])
print(s[0:])
print(s[0:6:2])
print('-------------------------')
print(s[0:-1:-2]) #显然不存在
print('-------------------------')
print(s[0:-1:2])
print(s[::-1])
#输出
长度为6
Genius
Genius
Geniu
Genius
Gnu
-------------------------
-------------------------
Gnu
suineG
[Finished in 1.2s]
可能仍有所不解,确实正负夹杂确实也把问题扯复杂了,可以看看这篇Python中切片的理解
5.2.2元组
元组(tuple)是一种序列(sequence)结构。
5.2.2.1创建元组
元组(tuple)是一种不可变序列,一旦创建就不能修改。创建元组可以使用tuple([iterable])函数或者直接用逗号(,)将元素分隔。
s1 = 21,22,23,24
print(type(s1))
# 创建元组时使用小括号把元素包裹起来不是必须的
print(s1)
print('------------------')
s2 = (21,22,23,24)
print(type(s2))
# 使用括号将元素包裹起来,这只是为了提高程序的可读性
print(s2)
print('------------------')
s3 =('abc',123,s1,'sub',s2,123,'Genius')
# 可迭代
print(type(s3))
print(s3)
print('------------------')
s4 =tuple([1,2,3,4])
# 元组还有通过tuple([iterable])函数创建,参数iterable是任何可迭代对象。
# 使用tuple()函数创建元组对象,实参是一个列表,列表是可迭代对象
print(type(s4))
print(s4)
print('------------------')
# 输出
<class 'tuple'>
(21, 22, 23, 24)
------------------
<class 'tuple'>
(21, 22, 23, 24)
------------------
<class 'tuple'>
('abc', 123, (21, 22, 23, 24), 'sub', (21, 22, 23, 24), 123, 'Genius')
------------------
<class 'tuple'>
(1, 2, 3, 4)
------------------
[Finished in 0.2s]
注:如果一个元组只有一个元素时,后面的逗号不能省略,即(21,)表示的是只有一个元素的元组,而(21)表示的是一个整数。另外,()可以创建空元组。
s1 = ()
print(type(s1))
print(s1)
print('-----------------')
s2 = (21)
print(type(s2))
print(s2)
print('-----------------')
s3 = (21,)
print(type(s3))
print(s3)
#输出
<class 'tuple'>
()
-----------------
<class 'int'>
21
-----------------
<class 'tuple'>
(21,)
[Finished in 0.3s]
5.2.2.2访问元组
元组做为序列可以通过下标索引访问元素,也可以对其进行分片。
s1 = 21,22,23,24
s2 = (21,22,23,24)
s3 =('abc',123,s1,'sub',s2,123,'Genius')
print(s3[1:3])
#输出
(123, (21, 22, 23, 24))
[Finished in 0.2s]
元组还可以进行拆包(Unpack)操作,就是将元组的元素取出赋值给不同变量。
s1 = 21,22,23,24
s2 = (21,22,23,24)
s3 =('abc',123,s1,'sub',s2,123,'Genius')
str1,int1,*n=s3
print(str1)
print(int1)
print(n)
print(type(n))
#输出
abc
123
[(21, 22, 23, 24), 'sub', (21, 22, 23, 24), 123, 'Genius']
<class 'list'>
[Finished in 0.3s]
注:将元组s3进行拆包操作,接收拆包元素的变量个数应该等于元组个数相同。否则,如上接收变量个数只有3个,最后一个很特殊变量n前面有星号,表示将剩下的元素作为一个列表赋值给变量n。
5.2.2.3遍历元组
s1 = 21,22,23,24
s2 = (21,22,23,24)
s3 =('abc',123,s1,'sub',s2,123,'Genius')
for item in s3:
print(item)
print('--------------------')
for index,item in enumerate(s3):
print('{0}--{1}'.format(index,item))
#enumerate(a)函数可以获得元组对象,
#该元组对象有两个元素,第一个元素是索引,
#第二个元素是数值。所以index, item是元组拆包过程
#输出
abc
123
(21, 22, 23, 24)
sub
(21, 22, 23, 24)
123
Genius
--------------------
0--abc
1--123
2--(21, 22, 23, 24)
3--sub
4--(21, 22, 23, 24)
5--123
6--Genius
[Finished in 0.3s]
注:虽然介绍的是元组的遍历,上述遍历方式适合于所有序列,如字符串、范围和列表等。
5.2.3列表
列表(list)也是一种序列结构,与元组不同列表具有可变性,可以追加、插入、删除和替换列表中的元素。
5.2.3.1列表创建
创建列表可以使用list([iterable])函数,或者用中括号[]将元素包裹,元素之间用逗号分隔。
s1 = [21,22,23,24]
# 注意中括号不能省略,如果省略了中括号那就变成了元组了。
print(type(s1))
print(s1)
print('-------------')
#s2 =[]
# 创建空列表是[]表达式。
s2=[1]
# 只有一个元素的列表,
# 中括号不能省略。另外,无论是元组还是列表,
# 每一个元素后面都跟着一个逗号,
# 只是最后一个元素的逗号经常是省略的
print(s2)
print('-------------')
s3 =['abc',123,s1,'sub',123,'Genius']
# 列表中可以放入任何对象,
print(type(s2))
print(type(s3))
print(s3)
print('-------------')
s4 =list((1,2,3,4))
# 通过list([iterable])函数创建,
#参数iterable是任何可迭代对象。
#代码是使用list()函数创建列表对象,
#实参是一个元组,元组是可迭代对象,
#可以作为list()函数参数创建列表对象。
print(type(s4))
print(s4)
#输出
<class 'list'>
[21, 22, 23, 24]
-------------
[1]
-------------
<class 'list'>
<class 'list'>
['abc', 123, [21, 22, 23, 24], 'sub', 123, 'Genius']
-------------
<class 'list'>
[1, 2, 3, 4]
[Finished in 0.6s]
5.2.3.2追加元素
列表中追加单个元素可以使用append()方法追加单个元素。如果想追加另一列表,可以使用+运算符或extend()方法。
l1 =[1,2,3]
print(l1)
l1.append(4)
print(l1)
l2 =[5,6,7]
l1.extend(l2)
# l1+=l2
print(l1)
#输出
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5, 6, 7]
[Finished in 0.3s]
5.2.3.3插入元素
插入元素可以使用列表的insert()方法,该方法可以在指定索引位置,插入一个元素。
l1 =[1,2,3]
l1.insert(1,10)
print(l1)
#输出
[1, 10, 2, 3]
[Finished in 0.3s]
5.2.3.4替换元素
列表具有可变性,其中的元素替换,替换元素很简单,通过列表下标索引元素放在赋值符号(=)左边,进行赋值即可替换。
l1 =[1,2,3]
l1[0]=100
print(l1)
#输出
[100, 2, 3]
[Finished in 0.3s]
5.2.3.5 删除元素
列表中实现删除元素的方式有两种:一种是使用列表的remove()方法;另一种是使用列表的pop()方法。
(1) remove()方法
remove()方法从左往右查找列表中的元素,如果找到匹配元素则删除,注意如果找到多个匹配元素,只是删除第一个。如果没有找到则会抛出错误。
lis =[1,2,3,4,5]
print(lis)
lis.remove(1) #传入元素值
print(lis)
lis.remove(1) # 报错
print(lis)
#输出
[1, 2, 3, 4, 5]
[2, 3, 4, 5]
Traceback (most recent call last):
File "C:\Users\dell\Desktop\test.py", line 5, in <module>
lis.remove(1)
ValueError: list.remove(x): x not in list
(2) pop()方法
pop()方法也会删除列表中的元素,但它会将成功删除的元素返回。pop()方法语法如下:
lis =[1,2,3,4,5]
print(lis.pop()) #参数是指定删除元素的索引
print(lis.pop(2)) #可以省略,表示删除最后一个元素。
#输出
5
3
[Finished in 0.3s]
5.2.3.6 其他常用方法
- reverse()。倒置列表。
- copy()。复制列表。
- clear()。清除列表中的所有元素。
- index(x[, i[, j]])。返回查找x第一次出现的索引,i是开始查找索引,j是结束查找索引。该方法继承自序列,元组和字符串也可以使用该方法。
- count(x)。返回x出现的次数。该方法继承自序列,元组和字符串也可以使用该方法。
lis =[1,2,1,3,4,1,5]
lisc=lis.copy() #复制
lis.clear() #清空
print(lis)
print(lisc)
lisc.reverse() #翻转
print(lisc)
print(lisc.index(1))
print(lisc.index(1,5,7))
print(lisc.count(1))
#输出
[]
[1, 2, 1, 3, 4, 1, 5]
[5, 1, 4, 3, 1, 2, 1]
1
6
3
[Finished in 0.3s]
5.2.3.7 列表推导式
Python中有一种特殊表达式——推导式,它可以将一种数据结构作为输入,经过过滤、计算等处理,最后输出另一种数据结构。根据数据结构的不同分为:列表推导式、集合推导式和字典推导式。本节先介绍列表推导式。
如果想获得0~9中偶数的平方数列,那么可以通过for循环实现,代码如下:
lis = []
for i in range(10):
if(i%2==0):
lis.append(i**2)
print(lis)
lis2 = [i**2 for i in range(10) if(i%2==0)]
print(lis2)
#输出
[0, 4, 16, 36, 64]
[0, 4, 16, 36, 64]
[Finished in 0.4s]
列表推导式语法结构,如下图:
其中in后面的表达式是“输入序列”;for前面的表达式是“输出表达式”它运算结果会保存一个新列表中;if条件语句是过滤输入序列,符合条件的才传递给输出表达式,“条件语句”是可以省略的,也是所有元素都传递给输出表达式。
条件语句可以包含多个条件,如果想找出0~99之间的偶数,而且可以被5整除数列,实现代码如下:
lis2 = [i for i in range(100) if(i%2==0) if(i%5==0)]
# 两个条件是与关系
print(lis2)
#输出
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
[Finished in 0.3s]
5.2.4集合
集合(set)是一种可迭代的、无序的、不能包含重复元素的数据结构,集合又分为可变集合(set)和不可变集合(frozenset)
注:如果与序列比较,序列中的元素是有序的,可以重复出现,而集合中是无序的,不能重复的元素。序列强调的是有序,集合强调的是不重复。当不考虑顺序,而且没有重复的元素时,序列和集合可以互相替换。
5.2.4.1 创建可变集合
可变集合类型是set,创建可变集合可以使用set([iterable])函数,或者用大括号{}将元素包裹,元素之间用逗号分隔。
set1 ={1,2,3,1,2,4}
print(set1)
set2= set((1,2,3,1,2,4))
print(len(set2))
set3 ={} #创建一个空的集合不能使用{}表示
print(type(set3))
set4 =set() #而是使用空参数的set()函数
print(type(set4))
#输出
{1, 2, 3, 4}
4
<class 'dict'>
<class 'set'>
[Finished in 0.3s]
5.2.4.2 修改可变集合
可变集合类似于列表,可变集合内容可以被修改,可以插入和删除元素。修改可变集合几个常用的方法。包括:
- add(elem)。添加元素,如果元素已经存在,则不能添加,不会抛出错误。
- remove(elem)。删除元素,如果元素不存在,则抛出错误。
- discard(elem)。删除元素,如果元素不存在,不会抛出错误。
- pop()。删除返回集合中任意一个元素,返回值是删除的元素。
- clear()。清除集合。
set1 ={1,2,3,1,2,4}
print(set1)
set1.add(5)
print(set1)
print(set1.pop())
set1.remove(3)
print(set1)
set1.clear()
print(set1)
set1.discard(3)
set1.remove(3)
#输出
{1, 2, 3, 4}
{1, 2, 3, 4, 5}
1
{2, 4, 5}
set()
Traceback (most recent call last):
File "C:\Users\dell\Desktop\test.py", line 11, in <module>
set1.remove(3)
KeyError: 3
[Finished in 0.3s]
5.2.4.3 遍历集合
集合是无序的,没有索引,不能通过下标访问单个元素。但可以遍历集合,访问集合每一个元素。
set1 ={1,2,3,1,2,4}
for i in set1:
print(i)
for i,v in enumerate(set1,1):
print(i,v)
#输出
1
2
3
4
1 1
2 2
3 3
4 4
[Finished in 0.3s]
5.2.4.4 不可变集合
不可变集合类型是frozenset,创建不可变集合使用frozenset([iterable])函数,不能使用大括号{}。
set1= frozenset({1,2,3})#因为集合也是可迭代对象
print(type(set1))#可以作为frozenset()的参数
a= (1,2,3,4)
set2= frozenset(a)#元组作为frozenset()的参数
print(type(set2))
set1.add(1) #不变集合,不能被修改
#输出
<class 'frozenset'>
<class 'frozenset'>
Traceback (most recent call last):
File "C:\Users\dell\Desktop\test.py", line 6, in <module>
set1.add(1)
AttributeError: 'frozenset' object has no attribute 'add'
[Finished in 0.3s]
5.2.4.5 集合推导式
集合推导式与列表推断式类似,区别只是输出结构是集合。
set1={i for i in range(100) if(i%2==0) if(i%3==0)}
print(type(set1))
print(set1)
list1= [1,3,5,2,1,2,5,7]
set2={i for i in list1 } #去除了重复元素
print(set2)
#输出
<class 'set'>
{0, 96, 66, 36, 6, 72, 42, 12, 78, 48, 18, 84, 54, 24, 90, 60, 30}
{1, 2, 3, 5, 7}
[Finished in 0.4s]
5.2.5字典
字典(dict)是可迭代的、可变的数据结构,通过键来访问元素的数据结构。字典结构比较复杂,它是由两部分视图构成的:一个是键(key)视图;另一个是值(value)视图。键视图不能包含重复元素的,而值集合可以,键和值是成对出现的。
5.2.5.1 创建字典
字典类型是dict,创建字典可以使用dict()函数,或者用大括号{}将“键:值”对包裹,“键:值”对之间用逗号分隔。
dict1 ={}
print(type(dict1))
dict2 ={1:"XXX",2:"GGG",3:"MMM"}
print(type(dict2))
# 参数为另外一个 字典
dict3 =dict({1:"XXX",2:"GGG",3:"MMM"})
print(type(dict3))
# 参数为另外一个 元组
dict4 =dict(((1,"XXX"),(2,"GGG"),(3,"MMM")))
print(type(dict4))
# 参数为另外一个 列表
dict5 =dict([(1,"XXX"),(2,"GGG"),(3,"MMM")])
print(type(dict5))
# zip()函数将两个可迭代对象打包成元组
dict6 =dict(zip([1,2,3],["XXX","GGG","MMM"]))
print(type(dict6))
#使用dict()函数创建字典还可以使用一种key=value
#key=value形式只能创建键是字符串类型的字典
#使用时需要省略包裹字符串的引号(包括双引号或单引号)
#若仅包含数字的字符串,无法使用,因为省略引号后
#被看做数字,就不符合要求了
dict7 =dict(a="abc",b="bcd",c="cde")
print(type(dict7))
print(len(dict7))
#输出
<class 'dict'>
<class 'dict'>
<class 'dict'>
<class 'dict'>
<class 'dict'>
<class 'dict'>
<class 'dict'>
3
[Finished in 0.2s]
5.2.5.2 修改字典
字典可以被修改,但都是针对键和值同时操作,修改字典包括添加、替换和删除“键:值”对。
dict1 ={1:"XXX",2:"GGG",3:"MMM"}
#访问
print(dict1[1])
#若存则修改
dict1[1]="Genius"
#若不存在则增加
dict1[4]="Genius"
print(dict1)
#删除 del是语句不是函数
del dict1[1]
#pop(key[, default])方法删除键值对
#如果键不存在则返回默认值(default)
print(dict1.pop(2))
print(dict1.pop(1,"未找到"))
#popitem()方法删除任意键值对
#返回删除的键值对构成的元组
print(dict1.popitem())
print(dict1)
#输出
XXX
{1: 'Genius', 2: 'GGG', 3: 'MMM', 4: 'Genius'}
GGG
未找到
(4, 'Genius')
{3: 'MMM'}
[Finished in 0.3s]
5.2.5.3 访问字典
字典还一些方法用来访问它的键或值,这些方法如下:
- get(key[, default])。通过键返回值,如果键不存在返回默认值。
- items()。返回字典的所有键值对。
- keys()。返回字典键视图。
- values()。返回字典值视图。
dict1 ={1:"XXX",2:"GGG",3:"MMM"}
print(dict1.get(1))
print(dict1.get(5))# 若dict1[5] 则报错
print(dict1.get(5,"不存在"))
print(dict1.items())
print(dict1.keys())
print(dict1.values())
#在访问字典时
#也可以使用in和not in运算符
#但是需要注意的是
#in和not in运算符只测试键视图中进行。
print(1 in dict1)
print(1 not in dict1)
#输出
XXX
None
不存在
dict_items([(1, 'XXX'), (2, 'GGG'), (3, 'MMM')])
dict_keys([1, 2, 3])
dict_values(['XXX', 'GGG', 'MMM'])
True
False
[Finished in 0.2s]
5.2.5.4 遍历字典
字典遍历也是字典的重要操作。与集合不同,字典有两个视图,因此遍历过程可以只遍历值视图,也可以只遍历键视图,也可以同时遍历。
dict1 ={1:"XXX",2:"GGG",3:"MMM"}
for key in dict1.keys():
print("key--"+str(key))
for value in dict1.values():
print("value--"+str(value))
for key,value in dict1.items():
print("key--{0},value--{1}".format(key,value))
#输出
key--1
key--2
key--3
value--XXX
value--GGG
value--MMM
key--1,value--XXX
key--2,value--GGG
key--3,value--MMM
[Finished in 0.3s]
5.2.5.5 字典推导式
因为字典包含了键和值两个不同的结构,因此字典推导式结果可以非常灵活
a = {1:"a",2:"b",3:"c"}
b ={ k:v for k,v in a.items() if(k>=2)}
print(b)
c =[ k for k,v in a.items() if(k>=2)]
print(c)
# 输出
{2: 'b', 3: 'c'}
[2, 3]
[Finished in 0.3s]