列表
容器型数据类型
即是可以一个数据内可存放多个其他数据的数据类型,像是个能装东西的容器。包括列表,元组,集合,字典等数据类型。
列表 (list)
定义
在Python中,列表是由一系元素按特定顺序构成的数据序列,这样就意味着定义一个列表类型的变量,可以保存多个数据,而且允许有重复的数据。跟上一课我们讲到的字符串类型一样,列表也是一种结构化的、非标量类型,操作一个列表类型的变量,除了可以使用运算符还可以使用它的方法。
列表的创建方法
那么如何创建一个列表呢,有如下4种方法:
-
最基本最简单的方法,和c语言定义数组一样,列表名 = [] ,[]内写列表中的元素,逗号分隔,最后一个元素后也可以写逗号。且可以使用 * 创建重复元素的列表。例如:
list1=[0]*5 # 结果是[0,0,0,0,0]
-
循环配合append()函数或是insert()函数或是使用列表的加运算或是input()这种输入函数创建列表。append函数是添加元素在列表末尾,inset函数可以指定插入位置。例如:
list1=[] for i in range(5): list1.append(i) # list1.insert(i,i) # 默认前面的参数是想要插入位数,后面的是插入的元素 # list1+=[i] # 结果都是[0, 1, 2, 3, 4] # 将循环体内的 i 改为int(input(f'请输入第{i+1}个元素')) (insert中只改右边的) # 即可手动输入列表中每个元素
-
列表的生成式 列表还可以通过一种特殊的字面量语法来创建,这种语法叫做生成式。例如:
list1 = [x for x in range(1, 10)] print(list1) # 结果 [1, 2, 3, 4, 5, 6, 7, 8, 9]
这种方式创建列表,几乎可以取代第二种创建方式,除非你要使用input手动输入每个元素,否则建议使用这种方式创建列表,不仅代码少了,而且生成式拥有更好的性能,建议用生成式语法来创建列表。
-
使用list()函数将数据转换成列表类型,例如:
a='1,234,567,89' list1=list(map(int,a.split(','))) print(list1) #[1, 234, 567, 89] list2=list(range(4)) # [0, 1, 2, 3] print(list2) list3=list(zip(list1,list2)) # [(1, 0), (234, 1), (567, 2), (89, 3)] print(list3)
除了可以转换这些数据,list还可以转换后面讲的元组,集合,字典(默认转 键,加.value 取值)等数据类型
列表的运算
列表的运算类似于字符串之间的运算,具体如下例说明
list1 = [12, 56, 42, 31, 45, 68] list2 = [16, 32, 46, 25] # 列表的拼接 list3 = list1 + list2 print(list3) # [12,56,42,31,45,68, 16,32,46,25] # 列表的重复 list4 = ['hello'] * 3 print(list4) # ['hello', 'hello', 'hello'] # 列表的成员运算 print(100 in list3) # False print('hello' in list4) # True # 获取列表的长度(元素个数) size = len(list3) print(size) # 10 # 列表的索引 print(list3[0], list3[-size]) # 12 12 list3[-1] = 100 print(list3[size - 1], list3[-1]) # 100 100 # 列表的切片 print(list3[:5]) # [12, 56, 42, 31, 45] print(list3[4:]) # [45, 68, 16, 32, 46, 100] print(list3[-5:-7:-1]) # [68, 45] print(list3[::-2]) # [100, 32, 68, 31, 56] # 列表的比较运算 list5 = [1, 2, 3, 4] list6 = list(range(1, 5)) # 两个列表比较相等性比的是对应索引位置上的元素是否相等(默认比较第一个元素,相同则依次往后) print(list5 == list6) # True list7 = [3, 2, 1] # 两个列表比较大小比的是对应索引位置上的元素的大小(默认比较第一个元素,相同则依次往后) print(list5 <= list7) # True
要注意索引运算时不能越界,否则会报错,而切片操作则无需担心越界,越界也不会报错,只会取能取到的,如果范围内没有元素则返回空列表。
列表元素的遍历
列表大体有如下三三种遍历方法,一般都是使用for循环
a=[range(8)] for i in a: print(i,end=' ') #只读遍历 for i in range(len(a)): #可以更改 print(a[i],end=' ') for i, x in enumerate(a): #同时获取序号 print(i+1,x)
第一种是循环变量依次等于变量中的每个元素以此遍历,好处是简单,不过不能获取元素序号,无法对元素进行更改;第二种就是循环变量等于列表的索引,并使用索引进行遍历,这种方法可以更改列表的元素,也可以获取列表的序号;不过可以更改有时候也不是优点,所以也可以使用enumerate()函数获取列表的索引与值,然后进行遍历。
列表的常用方法
列表有非常多的方法函数,下面简单介绍常用的几种
-
首先是之前说过的添加元素用的 append与insert两个,append是在列表最后加入元素,insert则可以在列表任意位置插入元素。例子可以参考定义方法2
-
有添加自然有删除,删除有以下几种方法
list1 = [12, 56, 11, 55, 32, 87] # 删除指定的元素,如果多个一样的值只删除第一个 list1.remove(56) print(list1) # [12, 11, 55, 32, 87] # 删除指定索引位置的元素,如果内容是空则删除最后一个 list1.pop(0) del list1[len(list1) - 1] print(list1) # [11, 55, 32] # 清空列表中的元素 list1.clear() print(list1) # []
第一种方法是remove方法,删除指定值的元素;第二种方法是按索引删除,有两种命令可以完成这一操作,分别是pip与del,两个命令使用方式略有不同,结果是一样的,不过pip会返回删除的元素,比如a=list1.pip(1)会在删除索引为1的元素同时把该元素赋值给a,del则不会,del的性能略优。
-
还有查找元素索引以及元素计数的方法 index 与count
list1 = [12, 12, 11, 12, 32, 87] print(list1.index(12)) # 查找元素,找到第一个就返回索引 print(list1.index(12, 1)) # 可设置从哪里开始找与找到哪里为止 print(list1.index(12, 3, 5)) print(list1.count(12)) # 计数一共有几个该元素
需要注意的是,index如果找不到元素会报错
-
元素排序与反转 使用sort与reverse
list1 = [12, 56, 11, 55, 32, 87] list1.sort() # 排序 print(list1) # [11, 12, 32, 55, 56, 87] list1.reverse() # 反转 print(list1) #[87, 56, 55, 32, 12, 11] print(list1[::-1]) # 切片反转,不会改变原列表 #[11, 12, 32, 55, 56, 87]
也可以使用切片操作的反转后 赋值给原列表
列表的嵌套
列表中不止可以放 各种字符与字符串,还可以放列表甚至后面说的元组,集合等等类型的数据,那么自然就可以实现列表中放列表,列表里面的列表还是列表的嵌套操作。这样的列表我们可以用于模拟多维数组或是矩阵。
但要特别注意不能用如下方式创建嵌套列表
cores = [[0] * 3] * 5 print(cores) # [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] #否则就会导致如下后果 cores[0][0] = 95 print(cores) # [[95, 0, 0], [95, 0, 0], [95, 0, 0], [95, 0, 0], [95, 0, 0]] #正确的应该这样创建 scores = [[0] * 3 for _ in range(5)] scores[0][0] = 95 print(scores) # [[95, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
原因和计算机数据存放有关,我就不多解释了,对此有兴趣的小伙伴可以去Python Tutor网站使用可视化运行上述代码查看。
小练习
-
手动输入三数后按从大到小顺序输出。(最好不要使用sort,尝试自己排序,最好最后再去了解一下经典的排序算法,例如冒泡,选择,插入等等。)
-
随机10个数(自选范围即可),输出其中第二大的数。
-
与机器玩火柴游戏,有21根火柴,人和机器轮流拿,每次拿1-4根,拿到最后一根的输,机器后手,保证机器赢。
拓展:可以思考一下第三题的变量,火柴数,每次拿的最大最小数,先后手,甚至最后一根的输赢判定,对游戏结果的影响。
-
写个斗地主发牌的程序,并显示每个玩家的手牌结果。
tips: 思考代码有没有优化空间,注意有没有使用上嵌套列表
-
尝试几种简单的排序,冒泡,选择,插入,最好再尝试他们的升级,冒泡的升级搅拌(鸡尾酒),插入的升级中插(折半插入),计数也可以了解一下,如果仍有余力可考虑尝试希尔、归并、快排,其他的排序算法如果有兴趣也可以自行了解,可以去 十大经典排序算法 了解。
tips: 冒泡就是,n个元素按顺序两两比较大小,如果大于(小于)就交换,直到一轮过去没有交换或n轮过去则排好了;选择则是每轮选出最小(大)的放在列表一端,然后在剩下元素中重复这样操作,就排序完成了;插入则是从第二个元素开始,每个元素和前一个元素比较,如果大于(小于)则将元素再往前比较,直到合适的位置插入,重复操作到最后一个元素就排好了。
搅拌则是,要求冒泡时,一轮从左往右冒泡,一轮从右往左冒泡,这样可以略微提高代码效率,让代码有更高机会提前结束,特别是应对一些就快排好序的数列时,这样的冒泡是最快的。
中插则是在插入时第一次和前一个比较后,如果大于(小于)就往前一半的位置插入,插入后和前后比较,大于(小于)前面则往前继续折半插入,小于(大于)后面则往后折半插入,直到合适位置然后继续下一个元素,直到最后一个元素插入完毕,折半插入是简单排序算法中平均性能最好的了。
计数排序则是和数据个数与数据范围相关,建立一个整个范围的列表,然后将每个数据加入这个列表,再把这些数据拿出来就是顺序的了。
-
自定义一个列表有重复元素的列表(可以考虑随机20个10以内的整数),删除其中重复元素。
-
自定义一个列表有重复元素的列表,找出其中重复最多的元素。
-
有一个已经排好序的放整数的列表(数字从小到大),输入要查找的数据,如果在列表中找到该数据,输出该数据在列表的下标(索引),否则输出“找不到该数据”(要求使用折半查找,即一开始找中间,如果不是则比较大小,大则往右半继续折半,小则往做,重复操作,直到找到为止)
-
(难度较高,不用勉强)有一个放整数的列表,其中有一个整数出现次数超过了半数以上,请找出该元素(要求时间复杂度不能大于n,也就是不是有两重甚至以上的循环,count,sort(直接就是二重循环,不能使用)等函数也算循环)