- 你也能看得懂的Python算法书
- 王硕 董文馨 张舒行 张洁编著
- 6467字
- 2020-08-27 22:22:52
1.3 列表
列表是Python中五种标准变量类型的一种。一系列按顺序排列的元素组成了列表,一个列表中可以包含字符、数字、字符串,甚至子列表。
在Python中,同一个列表中可以包含多个不同类型的元素,也就是说,不同类型的变量可以存在于同一个列表内,如图1.13所示。列表的长度以及列表内元素的值都是动态的—它们可以随时被修改。
图1.13 包含列表的列表(list4)
1.3.1 定义列表
在Python中,列表用中括号表示([])。
下面的程序中定义了4个不同的列表:
01 list1=[]
02 list2=[2,3,5,7]
03 list3=["a","b","c"]
04 list4=[1,4,2,"a",[2,3,5]]
很明显,list1是一个空列表,它的内部不包含任何元素。通常在需要提前声明变量类型为列表的情况下,用定义空列表来实现。第2行的list2是一个整数列表,它的每一个元素都是一个整型变量,而list3中的每一个元素都是一个字符串。最后,list4是一个包含多种元素的列表,可以看到,它内部有数字、字符串和列表这三种元素。
1.3.2 对元素进行操作
现在已有一个包含多种元素的列表:
01 mylist=[2,3,5,7,11,13,17,19,"integer","string","list",[123,456]]
列表内包含多种元素,那么如何调用这些列表内的元素进行计算和拼接等工作呢?
由于列表是一个有序集合,所以可以根据索引来找到每一个元素。元素的格式是列表的名称+[索引],索引从0开始。比如,列表mylist的第一个元素就是mylist[0]。因为第一个元素的索引为0,所以最后一个元素的索引应该是列表的长度减1,如图1.14所示。
图1.14 列表mylist
如果列表中的元素还是一个列表,那么如何调用子列表内的元素呢?很简单。比如在列表mylist中,最后一个元素是mylist[11],这个元素是一个列表。那么,这个子列表的第一个元素就是mylist[11][0]。
下面是对列表mylist内的元素进行的一些操作,并对结果进行输出:
01 mylist=[2,3,5,7,11,13,17,19,"integer","string","list",[123,456]]
02 print(mylist[11][0]/mylist[1])
03 print(mylist[8]+" "+mylist[9])
运行程序,输出结果为:
41.0
integer string
其中,mylist[11][0]是指 mylist 中第12个元素(子列表)的第1个元素,也就是123;mylist[1]是指mylist的第2个元素,也就是3。它们相除的商就是41.0。同理,mylist[8]和mylist[9]是指列表中的第9个元素和第10个元素,它们和一个空格拼接起来,就成了输出结果的第2行“integer string”。
也可以修改列表中元素的值:
01 mylist=[2,3,5,7,11]
02 mylist[4]=9
03 print(mylist,mylist[4])
运行程序,输出结果为:
[2,3,5,7,9]9
列表内的元素和变量一样,值可以被随时更新,也可以被用来赋值给其他变量。
列表中的元素个数是非固定、可以改变的。也就是说,可以往列表中添加新的元素,也可以把元素从列表中移除。先来看看如何往列表中添加元素。
给定一个元素为“2,3,5,7,13,17,19”的列表mylist,这个列表内的所有元素都是质数。要想把这个列表转换为从2到23的有序质数列表,就要用到append和insert这两个内置列表函数。
如图1.15和图1.16所示,内置函数append的功能是在列表的末尾插入新的元素,而函数insert的功能是在指定索引的位置插入新的元素,原本在这个索引位置处的元素及其后面的所有元素往后顺移一位。
图1.15 append函数
图1.16 insert函数
在下面的程序中,每往列表中添加一个元素,就把整个列表打印出来,方便观察规律:
01 mylist=[2,3,5,7,13,17,19]
02 mylist.append(23)
03 print(mylist)
04 mylist.insert(4,11)
05 print(mylist)
运行程序,输出结果为:
[2,3,5,7,13,17,19,23]
[2,3,5,7,11,13,17,19,23]
可以看到,在append函数执行完毕后,列表的长度增加了一位,23被加在了列表的最后。而insert函数执行完后,新元素11被插到索引为4的位置,也就是mylist[4]的位置—第5个元素。原本排在第5个的元素13并没有消失,它和它后方的元素全部往后移动了一位,也就是索引增加了1。由这个例子也可以看出,列表内置函数的调用方法是:列表名+句点+函数名+小括号,括号内是函数执行所需要的数据。
append函数的括号中填写需要插入在列表末尾的元素,insert函数括号中的第一个数据填写要插入的索引值,第二个数填写需要插入的元素,中间用逗号隔开。这些语法都是固定的,只有按照正确的方法编写程序才能按照设想运行。
再来看看如何从列表中移除元素。
如果要移除列表中的元素,有两个函数可以选择:remove和pop。remove函数的标准格式为:list.remove(obj),它的功能是移除指定列表(list)中某个值(obj)的第一个匹配项。pop函数的标准格式为:list.pop(index),它的功能是移除指定列表(list)中某个索引位置(index)上的元素,同时也返回被移除的元素的值。这两种函数运行完毕—指定元素被移除后,它后方的所有元素向前移动一位,也就是索引减少1,如图1.17所示。
图1.17 移除元素
下面是一个具体的例子:
01 mylist=[2,3,4,5,6,2]
02 mylist.remove(2)
03 print(mylist)
04 num=mylist.pop(0)
05 print(mylist,num)
运行程序,输出结果为:
[3,4,5,6,2]
[4,5,6,2]3
在这段程序中,remove函数移除了列表mylist中匹配到的第一个等于2的元素。由于列表的遍历顺序是按索引大小从小到大进行的,被移除的是第一个2,而不是最后的2。第4行中的pop函数移除了当前列表索引为0的数,也就是第一个数3,同时把3返回。
编写程序时我选择用变量num“接住”传输回来的元素,并将它和pop操作后的列表一起输出,这就叫弹出元素。弹出功能可以在我们需要一次性使用列表中的数时使用(用完一次就丢掉)。
也可以选择不用变量保存pop的返回值,而把它单纯地作为一个用于移除元素的函数使用。如果pop的括号内没有填写要弹出的元素的索引(空括号),则默认弹出列表的最后一个元素。
要移除列表中的元素还有一个方法:
01 numbers=[1,2,3,4,5,6]
02 del numbers[2]
03 print(numbers)
运行程序,输出结果为:
[1,2,4,5,6]
del函数的使用格式为“del+空格+要删除的元素”,它和pop函数的删除方法相似,需要提供列表名和索引,但它没有pop函数返回被删除的元素值的功能。
1.3.3 列表的顺序
我们常常需要把字符串或者数字按首字母顺序和数字大小排序。如何把大小随机的元素按顺序排列呢?如图1.18所示。
图1.18 排序
只需要一步:
01 mylist=[2,3,5,29,13,17,19]
02 mylist.sort()
03 print(mylist)
运行程序,输出结果为:
[2,3,5,13,17,19,29]
经过列表内置函数 sort 的操作后,mylist 被进行了永久性的从小到大的排序—原来的顺序无法复原了。如果列表里的元素都是字符串,则Python会自动按首字母从a到z的顺序排列。需要注意的是,如果用sort函数进行排序,那么列表内的元素必须都是同一种类型,否则程序会出错。
那么,如果想要从大到小排序呢?
01 mylist=[2,3,5,29,13,17,19]
02 mylist.sort()
03 mylist.reverse()
04 print(mylist)
运行上面的程序,输出结果为:
[29,19,17,13,5,3,2]
在这段程序中,首先用sort函数对mylist进行了永久性的从小到大排序,然后用内置函数reverse把整个列表的元素的顺序全部反过来。也就是说,对mylist使用了reverse函数后,最后一个元素变成了第一个元素,倒数第二个元素变成了第二个元素,依此类推。和sort函数相同,reverse函数的反转操作也是永久性的。在sort函数的括号中可以填入其他函数并按照函数内部规定的方法排序,如图1.19所示。
图1.19 从大到小排序
1.3.4 列表内置函数
除了前面几节讲到的append、insert、remove等内置函数,列表还有很多其他非常实用的内置函数。
首先要讲的是len函数。函数的名字“len”其实是英文单词length的缩写。length是长度的意思,顾名思义,这个函数是用来求列表的长度的。下面是一段使用len函数的例子:
01 mylist=[2,3,5,29,13,17,19]
02 L=len(mylist)
03 print(L)
运行程序,输出结果为:
7
函数len的使用格式是len(列表名),它会返回列表的长度,也就是列表里元素的个数。在上面的程序中,列表的长度是7。由于len函数有返回值,所以如果你想多次使用它,最好用一个变量存储它的值。如果只是想要输出,可以忽略第2行,直接调用print(len(mylist))就可以了。
接下来要了解的是max函数和min函数。这两个函数可以找出列表中的最大值和最小值:
01 mylist=[2,3,5,29,13,17,19]
02 print(max(mylist),min(mylist))
运行以上程序,输出结果为:
29 2
同样,如果想要多次使用max函数或min函数返回的值进行计算,也要用一个新的变量存储它们的值。
第4个要介绍的函数是count,它是用来统计指定元素在指定列表中的出现次数的函数:
01 mylist=[2,3,5,29,13,17,19,2,2,3]
02 print(mylist.count(2),mylist.count(3),mylist.count(19))
运行以上程序,输出结果为:
3 2 1
count函数的使用格式为:列表名+句点+函数名(count)+括号(括号内为需要统计出现次数的元素的值)。可以看到,在列表mylist中,值为2的元素有3个,值为3的元素有2个,值为19的元素有1个,所以 count函数的返回值分别为3、2、1。如果指定元素在列表中不存在,那么count函数的返回值为0。
第5个函数是index函数,它可以在列表中找出与指定值匹配的第1个元素的索引位置。
01 mylist=[6,2,8,7,2,3,4]
02 print(mylist.index(2))
运行以上程序,输出结果为:
1
根据前面讲到的几个内置函数的规律,index函数也有返回值,使用格式也和count函数相似,括号内是需要查找的元素的值。在列表mylist中,第一个值为2的元素是第2个元素,也就是说,索引是1,所以index函数返回了1。即使索引为4的元素的值也是2,但是由于它并不是第一个匹配的元素,所以index不会返回它的值。
第6个函数是clear函数,它可以把列表清空:
01 numbers=[1,2,3,4,5,6]
02 numbers.clear()
03 print(numbers)
运行以上程序,输出结果为:
[]
clear函数的使用格式为:列表名+句点+clear()。clear函数不需要额外的数据。
最后要讲到的函数是copy函数,copy函数的功能是复制原有的列表。
说到复制列表,大家心里应该已经有了一些不用这个函数也可以进行复制的思路:
01 numbers=[1,2,3,4,5,6]
02 copylist=numbers
03 print(numbers,copylist)
这段程序的输出结果为:
[1,2,3,4,5,6][1,2,3,4,5,6]
输出结果一样,是不是就复制成功了呢?
我们来看看对复制完的列表中的元素进行改动会如何:
01 numbers=[1,2,3,4,5,6]
02 copylist=numbers
03 copylist.pop()
04 print(numbers,copylist)
输出结果为:
[1,2,3,4,5][1,2,3,4,5]
你会发现,只移除了 copylist 列表的最后一个元素,可是 numbers 列表的最后一个元素也被移除了。如果复制成功,两个列表应该是两个互不影响的个体,这又是为什么呢?
这是因为Python中列表存储的方法和其他语言中的不太一样,列表中的元素在计算机的存储空间中占据一定的内存,而列表本身存储的是这些元素的存储地址,在调用列表元素的时候根据地址来调出它们原本的值。如果直接给新的列表赋值,只是复制了原来列表存储的地址,所以元素本身并没有被复制成两份,如图1.20所示。
图1.20 复制列表
要复制元素本身就需要使用内置函数copy:
01 numbers=[1,2,3,4,5,6]
02 copylist=numbers.copy()
03 copylist.pop()
04 print(numbers,copylist)
运行这段程序,输出结果为:
[1,2,3,4,5,6][1,2,3,4,5]
copy函数返回的是复制原列表中的元素后产生的一组新元素的存储地址,其被存储在新的列表中。这样,修改复制后的列表中的元素就不会影响到原来的列表了,如图1.21所示。
图1.21 copy函数的效果
1.3.5 截取和拼接列表
当只需要使用列表的一部分或想把两个列表合并成一个时,可以对列表进行截取和拼接操作。下面是对列表进行截取操作的演示程序:
01 numlist=[2,3,4,6,1,3,5,7,9,10,22,18,31,24,53]
02 print(numlist[:5],numlist[2:5],numlist[5:])
运行程序,输出结果为:
[2,4,3,6,1][4,6,1][3,5,7,9,10,22,18,31,24,53]
截取操作过程如图1.22至图1.24所示。
图1.22 完整的列表numlist
图1.23 numlist[:5]
图1.24 numlist[2:5]
截取列表的方式为:列表名+[m:n],其中 m 必须小于 n,否则截取到的列表为空。截取到的元素范围为列表中索引值从m到n-1的元素。如果没有填写m,则m默认为0,也就是从列表的开头截起,如果n没有填写则n默认为列表的长度(len(列表名)),也就是截取到列表的结尾。
列表也可以被拼接:
01 numlist=[2,3,4,6,1,3,5]
02 newlist=numlist[:5]+numlist[2:5]
03 print(newlist)
运行程序,输出结果为:
[2,3,4,6,1,4,6,1]
拼接操作如图1.25所示。
图1.25 截取的列表片段相加
新的列表是旧的两个列表拼接起来得到的,这两个列表可以用截取的方式截出,也可以是一个列表变量或者函数返回的列表。和直接赋值不同,对拼接得到的列表进行改动不会影响原来的两个列表。
1.3.6 字符串、元组和列表
这三种变量类型其实有很多相似之处。在讲解这些相似处之前,我们先来了解元组这种变量类型。
元组和刚刚学习的列表十分相似,它们都是Python五种标准变量类型中的一种,也同样是序列类型的变量,即由有序排列的空、单个或多个元素组成的变量,它们内部的元素都可以被调用,元素的种类可以不同。它们的不同之处在于,元组中的元素是固定不变的,它们的值不能被更改。元组的长度也是固定的,即不能添加或删除元素。
我们使用小括号来定义元组。元组和列表一样,可以进行拼接和截取:
01 numtuple=(2,4,6,8,10)
02 print(numtuple)
03 newtuple=numtuple*2
04 print(newtuple)
05 print(newtuple[2:5])
运行程序,输出结果为:
(2,4,6,8,10)
(2,4,6,8,10,2,4,6,8,10)
(6,8,10)
程序中的第三行,numtuple*2相当于numtuple+numtuple。
元组可以被重复赋值,但是其中的元素不可以被更改:
01 numtuple=(2,4,6,8,10)
02 print(numtuple)
03 numtuple=(2,4,6,8)
04 print(numtuple)
05 print(numtuple[0])
06 #非法操作:
07 #numtuple[0]=100
08 #numtuple.append(10)
运行程序,输出结果为:
(2,4,6,8,10)
(2,4,6,8)
2
由此可见,元组的合法操作和列表完全相同。以上程序用注释写出了两个对元组非法操作的例子。如果这两条语句不是注释,则程序运行的时候会出错。所以,要想修改元组内部元素,只能给元组重新赋值或者在定义元组的那一行直接修改程序。
我们熟悉的字符串其实也与元组十分相似。可以把字符串描述成由一个或多个字符组成的元组,它不能被修改,但可以被截取、拼接或者赋值。但是,字符串只能由字符构成,而元组可以由多种类型的变量构成,如图1.26所示。
图1.26 字符串的结构
下面的程序演示了字符串的截取、拼接功能的使用:
01 str1="abcd"
02 print(str1[0],str1[1])
03 print(str[1:3])
04 print(str1[1:3]+str1[:2])
运行程序,输出结果为:
a b
bc
Bcab
字符串、元组和列表是可以相互转换的。这时候要用到str、list和tuple函数,这三个函数可以返回转换后的字符串、列表和元组。我们来看一个字符串转换为元组和列表的例子:
01 sample="abcdefg"
02 print(list(sample),tuple(sample))
运行程序,输出结果为:
['a','b','c','d','e','f','g']
('a','b','c','d','e','f','g')
可以看到,字符串中的每一个字符都被转换成单个元素存储在列表和元组中。任何字符串都可以转换为列表和元组。
再来看看列表转元组、元组转列表以及列表和元组转字符串的例子:
01 list1=["abcdefg","hijk"]
02 tuple1=(1,2,3,4,5)
03 print(tuple(list1),list(tuple1))
04 print(str(list1),list(tuple1))
05 del list1[0]
06 tuple=(1)
07 print(str(list1),str(tuple))
运行程序,输出结果为:
('abcdefg','hijk')[1,2,3,4,5]
['abcdefg','hijk'](1,2,3,4,5)
hijk
1
可以看出,列表和元组相互转换没有任何问题,而元组和列表转字符串时会有不同的情况出现。当列表或元组内有多个元素时,它们转成的字符串中会包括定义时输入的所有字符,包括中括号、小括号、逗号和用于表示字符串的引号。当列表或元组内只有一个元素时,这个元素会转成正常的字符串,不包含中括号或小括号或者用于标记字符串的引号。
1.3.7 用循环遍历列表
如果想要把列表中的值依次拿出来使用或者依次输入,可以用for循环遍历列表。
先来看一道题目:写一段程序,让用户把整数输入到列表中,再把列表内的整数全部相乘。
首先,编写一段程序让用户输入数字,并把它们加入列表:
运行程序,自己输入一些数据,对照输出结果检查程序是否正确。
然后,继续编写程序,把整个列表中的数相乘。
运行程序,输入数据,检查输出结果是否符合预期。
由于任何数乘0都等于0,所以result的初始值只能为1。同时,由于列表内元素的下标从0开始到长度减1,所以可以直接用range(total)来设定循环范围。
这道题还有另一种做法:
这段程序的运行结果与上一段相同,但让列表内数据相乘的方法却不同。i循环的范围是列表numbers,那么i每一次循环时的值就是列表中的某个元素:第1次循环时i==numbers[0],第2次循环时i==numbers[1]等。这样,每次循环直接把result乘上i就可以了。
1.3.8 字典简介
字典也是Python五种基础变量类型中的一种,它和列表一样,可以同时存储多个任意类型的元素,所以放在列表这里进行讲解。但是,比起相同之处,它和列表的不同之处更多。现实中的字典,比如英汉词典,是用来根据英语单词来找它对应的中文释义的,而Python中的字典是根据输入的关键字在内部寻找对应的值并返回,如图1.27和图1.28所示。
图1.27 字典
图1.28 字典中元素的调用和顺序及大小无关
就像列表使用中括号,元组使用小括号一样,定义字典或给变量赋值字典时使用大括号{}。
通过下面这一段程序来了解元组的定义和使用。
运行这段程序,输出结果为:
{1:'a',2:'b',4:'d',3:'c','a':123}
b d 123
定义字典时,每个元素叫作一个键值对,用x:y的形式定义,其中x为每个元素的关键字,也就是键;y 为元素储存的值。键在字典中必须是唯一且不可变的,而不同键代表的值可以是任意数据类型,也可以有相同的值存在。
使用字典时,和列表不一样,在中括号的内部输入的不是元素的索引值,而是元素的键。比如,键2所对应的值是字符串"b",那么输出letters[2]就是输出"b"的意思;同理,键4和键"a"也是一样的。如果中括号内的键在字典中不存在,那么程序会报错。想要更改键所对应的值,方法为:比如letter[4]="m",这样键4所对应的值就从之前的"d"变为了"m"。
也可以在字典中添加新的元素,但方法和我们之前了解的有点不同。添加新元素的办法是添加新的键,不需要使用append函数:
01 letters={1:"a",2:"b",4:"d",3:"c"} #给字典定义一个初始值
02 letters[5]="e" #给字典加入新的元素(键值对)
03 letters["abc"]=6
04 print(letters) #输出字典
运行程序,输出结果为:
{1:'a',2:'b',4:'d',3:'c',5:'e','abc':6}
用程序中的这种格式编写代码,新的键值对就会自己出现在字典中了。
可以对列表使用的函数len、del、clear和copy等,对字典也可以使用,方法是相同的。它还有更多的功能等待你去了解。