列表基础及相关

一、列表使用【重点掌握】

1.概念

变量:使用变量存储数据,但是,缺点:一个变量每次只能存储一个数据

思考:如果一次性存储多个数据,怎么做?

实际问题:存储5个人的年龄,求他们的平均年龄,按照以前的方式解决:

age1 = 10
age2 = 18
age3 = 9
age4 = 15
age5 = 20
average = (age1 + age2 + age3 + age4 + age5) / 5

继续思考:如果要存储100,甚至1000个人的年龄呢?

解决方案:此时采用定义变量的方式会显得很麻烦,而Python提供了一种解决方案,使用列表进行多个数据的存储

作用:列表相当于是一个容器,可以同时存储多个数据

本质:列表是一个有序的集合

说明:有序指的就是有顺序【数据的存放的顺序和底层存储的顺序是相同的】

2.基本使用

2.1定义列表
1.定义列表
列表是一种数据类型,定义列表相当于定义一个列表的变量
语法:列表名 = [数据1....]
说明:列表使用list表示,但是,列表名不要直接使用list【list()】,建议listxxx或者xxxlist

a.定义空列表
list1 = []
print(list1)

b.定义非空列表
*注意:列表是有序的集合,数据的存放顺序和内存中的存储顺序相同
list2 = [34,6,56,57,7]
print(list2)

c.列表中可以存储重复数据
list3 = [22,33,44,22,22,22,22]
print(list3)

d.列表中可以同时存储不同类型的数据
list4 = ["hello",10,45.9,True]
print(list4)
2.2列表元素获取
2.列表元素的访问

"""
注意:
a.列表中存储的数据被称为元素
b.列表是有序的,所以列表中的元素被依次进行了编号,编号从0开始,
  这个编号被称为索引,下标或者角标
c.索引的取值范围:
        0 ~ 列表元素个数 - 1
        -1 ~ -(元素个数)
d.如果超出索引的范围,则会报错IndexError
"""
nameList = ["tom","jack","bob","rose","zhangsan"]
print(nameList)

a.获取元素
语法:列表名[索引]
n1 = nameList[2]
print(n1)
print(nameList[2])
print(nameList[4])

*注意1:如果使用了超出范围的下标,则会报错
print(nameList[10]) #IndexError: list index out of range 索引越界

*注意2:下标的表示可以使用正数【从左向右】,也可以使用负数【从右向左】
print(nameList[-1])
print(nameList[-5])

#print(nameList[-6]) #IndexError: list index out of range


nameList = ["tom","jack","bob","rose","zhangsan"]
print(nameList)

b.修改元素
语法:列表名[索引] = 值
print(nameList[1])
nameList[1] = "蔡徐坤"  #注意:修改列表元素相当于给变量重新赋值
print(nameList[1])

print(nameList)

#结论:列表是一种可变的数据类型,其中的元素可以随时修改
2.3列表基本操作
列表基本操作


#1.列表组合:+
list1 = [2,3,4]
list2 = [7,8]
print(list1 + list2)
print(list1)

#2.列表元素的重复:*
print(list1 * 3)
print(list1)

#结论:列表组合和列表元素的重复都是生成了一个新的列表,对原列表没有任何影响

print("=" * 30)


#3.判断元素是否在列表中:
# a.成员运算符【in , not in】,一般结合if语句和for循环使用
list3 = [2, 3, 4, 7, 8]
print(3 in list3)  #True
print(6 in list3)  #False

print(3 not in list3)  #False
print(6 not in list3)  #True

if 3 in list3:
print("3在列表中")

# b.身份运算符【is , is not】,判断两个变量的地址是否是同一个
a = 10
b = 10
print(a is b)   #True

list1 = [1,2,3]
list2 = [1,2,3]
print(list1 is list2)  #False
print(list1 == list2)  #True

"""
注意:
a.变量中实际存储的是地址
比如:10的地址假设为:2343455
a和b中存储的是2343455

list1和list2是两个容器,只是其中的内容相同
2.4列表切片
4.列表切片
概念:通过开始下标,结束下标以及步长获取一个子列表
语法:列表名[start:end:step]

a.start可以省略,默认从0开始
b.end可以省略,默认为最后一个下标
c.step可以省略,默认为1
d.可以根据具体的情况选择性省略
e.注意:前闭后开区间【包头不包尾】
list1 = [11,22,33,44,55,66,77,88,99]

a.获取指定区间,而且下标都是正数,省略step
sublist1 = list1[1:4]    #指定区间
sublist1 = list1[1:]    #从指定下标开始到结尾
sublist1 = list1[:4]    #从开头到指定下标

b.获取指定区间,而且下标都是正数,定义step
sublist1 = list1[1:4:2]
sublist1 = list1[1::2]
sublist1 = list1[:4:2]

list1 = [11,22,33,44,55,66,77,88,99]

c.获取指定区间,而且下标都是负数
sublist1 = list1[-1:-4]   #[]
sublist1 = list1[-1:]   #只获取最后一个元素
sublist1 = list1[:-4]  #[11, 22, 33, 44, 55]

sublist1 = list1[-1:-4:-1]
print(sublist1)
sublist1 = list1[-1::-1]
print(sublist1)
sublist1 = list1[:-4:-1]
print(sublist1)

sublist1 = list1[-4:-1:-1]
print(sublist1)
sublist1 = list1[-4::-1]
print(sublist1)
sublist1 = list1[:-1:-1]
print(sublist1)

list1 = [11,22,33,44,55,66,77,88,99]

print(list1[::])
print(list1[::1])
print(list1[::-1])   #倒序

切片

list1 = [11,22,33,44,55,66,77,88,99]

print(list1[-1])  #获取元素

一、一般情况
*注意:start和end写出来,遵循前闭后开
... -4 -3 -2 -1 0 1 2 3 4 ...
1.省略step
print(list1[0:3])   #[11, 22, 33]
print(list1[:3])    #[11, 22, 33]
print(list1[0:])   #[11, 22, 33, 44, 55, 66, 77, 88, 99]

list1 = [11,22,33,44,55,66,77,88,99]

2.start和end为负数
print(list1[-1:-4:1])
print(list1[-1:-4:])
print(list1[-1:-4:-1])

print(list1[-4:-1:1])   #[66 77 88]
print(list1[-4:-1:])    #[66 77 88]
print(list1[-4:-1:-1])  #[]

list1 = [11,22,33,44,55,66,77,88,99]

3.start和end为正数
print(list1[1:4:1])  #[22, 33, 44]
print(list1[1:4:])   #[22, 33, 44]
print(list1[1:4:-1])   #[]


4.start和end可以为正数,也可以为负数【特殊情况】
11 22 33 44 55 66 77 88 99   元素
0   1 2 3   4   5   6   7   8   正索引
-9 -8 -7 -6   -5 -4 -3 -2 -1   负索引

print(list1[1:-4])   #[22, 33, 44, 55]
print(list1[1:-4:-1])  #[]

print(list1[-1:4])   #[]
print(list1[-1:4:-1]) #[99, 88, 77, 66]
print(list1[-1:-5:-1]) #[99, 88, 77, 66]

总结:如果start和end没有省略,start + step的结果判断是否在指定区间内


二、特殊情况
list1 = [11,22,33,44,55,66,77,88,99]
1.
print(list1[100:])    # []

2.
print(list1[0:-1])   #[11, 22, 33, 44, 55, 66, 77, 88]
print(list1[0:8])    #[11, 22, 33, 44, 55, 66, 77, 88]


3.
print(list1[4:100])  #[55, 66, 77, 88, 99]
print(list1[4:])  #[55, 66, 77, 88, 99]

4.
print(list1[::1])  #[11, 22, 33, 44, 55, 66, 77, 88, 99]
print(list1[::-1]) #[99, 88, 77, 66, 55, 44, 33, 22, 11] 【面试题】,倒序

5
print(list1[-1:0])  #[]
print(list1[-1:0:-1]) #[99, 88, 77, 66, 55, 44, 33, 22]

6.
print(list1[-4::-1])

3.系统功能

函数 说明
len(list) 获取列表元素个数
max(list) 返回列表元素最大值
min(list) 返回列表元素最小值
list(seq) 将元组转换为列表
list.append(obj) 在列表末尾添加新的对象
list.count(obj) 统计某个元素在列表中出现的次数
list.extend(seq) 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
list.index(seq) 从列表中找出某个值第一个匹配项的索引位置
list.insert(index,obj) 将对象插入列表
list.pop(index) 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
list.remove(obj) 移除列表中某个值的第一个匹配项
list.reverse() 反向列表中元素
list.sort(key=None,reverse=False) 对原列表进行排序
list.copy() 复制列表
list.clear() 清空列表
Python中系统提供了一些操作列表的系统功能【函数】,可以帮助完成一些操作

列表是一种可变的数据类型,可以进行增删改的操作

1.增
a.list.append(x),在列表末尾追加一个元素,x可以是任意类型
list11 = [1,2,3]
list11.append(4)
list11.append(False)
list11.append("abc")
list11.append([33,55])
print(list11)

b.list.extend(x),在列表末尾追加一个元素,x必须是一个容器【集合,序列】
list12 = [1,2,3]
print(list12)
*注意:可迭代对象包括字符串,列表,元组,字典,集合
list12.extend(5)   #TypeError: 'int' object is not iterable可迭代对象
print(list12)

list12.extend([5])
print(list12)

list12.extend("abc")
print(list12)

总结;append和extend如果添加的是容器,append将容器直接添加进去,而extend只添加元素

c.list.insert(index,x),在列表的指定为值上插入指定的元素
list13 = [1,2,3]
print(list13)
list13.insert(1,10)
print(list13)

*注意:如果插入的时候index超出下标范围,则默认在列表末尾插入元素
list13.insert(6,8)
print(list13)

list13.insert(2,[33,55])
print(list13)

list13.insert(3,"hello")
print(list13)

总结:extend只能添加容器,而且将容器中的数据打碎加入,
append和insert可以添加任意类型的数据,直接加入

2.删
a.list.remove(x),移除列表中的指定元素,如果出现重复元素,只会删除一个
list21 = [1, 10, 2, 3, 8,2,2,2]
print(list21)
list21.remove(2)
print(list21)

*注意:如果元素不存在,则报错
list21.remove(666) #ValueError: list.remove(x): x not in list
print(list21)

b.list.pop(index=-1) ,删除指定位置上的元素,如果不给值,则默认删除最后一个元素
list22 = [1, 10, 2, 3, 8]
print(list22)
list22.pop()
print(list22)

list22.pop(1)
print(list22)

*注意1:使用了超出范围的下标,则报错
list22.pop(9) #IndexError: pop index out of range
print(list22)

*注意2:pop()返回被删除的元素
list22 = [1, 10, 2, 66, 8]
print(list22)
num = list22.pop(3)
print(num)
print(list22)

result = list22.remove(2)  #None
print(result)

总结:pop返回被删除的元素,remove返回为None


c.list.clear() ,清空
list22 = [1, 10, 2, 66, 8]
print(list22)
list22.clear()
print(list22)

3.改
a.list.reverse() ,反转【倒序】
list31 = [34,56,56,67,100,200]
list31.reverse()
print(list31)

list31 = [34,56,56,67,100,200]
print(list31[::-1])

b.list.sort(),排序,默认为升序排序
list32 = [100,34,200,56,56,67]
print(list32)
升序
list32.sort()
print(list32)

降序
list32.sort(reverse=True)
print(list32)

字符串列表排序
list33 = ["456","abc","Kuf","helloabcbbv","xvya","888"]
print(list33)
list33.sort()
print(list33)

不同类型的元素是否可以排序----》不可以,因为sort底层采用的是关系运算符,不同类型无法比较
# list34 = [45,"faf","lll","5757",False,"你好"]
# list34.sort() #TypeError: '<' not supported between instances of 'str' and 'int'

4.查
a.len(list):获取列表中的元素个数/获取列表的长度
list41 = [4,6,56,56,76,6]
print(len(list41))

b.max(list):获取列表中的元素的最大值
 print(max(list41))
c.min(list):获取列表中的元素的最小值
print(min(list41))

d.list.count(x),获取元素x在列表中出现的次数
print(list41.count(56))
c = list41.count(56)
print(c)

e.list.index(x),获取元素x在列表中第一次出现的下标【从左往右】
list41 = [4,6,56,56,76,6]
i1 = list41.index(56)
print(i1)

*注意:如果元素不存在,则报错
# i1 = list41.index(100)   #ValueError: 100 is not in list

4.列表嵌套

列表的嵌套,其实就是一个列表中的元素又是一个列表

注意:操作嵌套列表,只要把要操作元素的下标当作变量名来使用即可

二、列表相关

1.列表拷贝

1.1内存中的变量

Python中的数据都是保存在内存中

Python中的数据分为两大类:

不可变数据类型:数字,布尔,元组,字符串

可变数据类型:列表,字典,集合

1.不可变数据类型
a = 10
b = a
print(a,b)
print(id(a),id(b))
a = 20
print(a,b)   #20 10
print(id(a),id(b))


2.可变数据类型
list1 = [22,33,44]
list2 = list1
print(list1,list2)
print(id(list1),id(list2))
*注意:更改的是容器的内容,并不是容器本身
list1[1] = 100
list1 = [45,6,7]
print(list1,list2)
print(id(list1),id(list2))

3.id(x):获取变量x在内存中的地址
如果两个变量的id()值相等,则说明表示同一个数据

①变量其中实际存储了一个数据的地址

②变量被称为引用
a------》4362284320 10的地址
b------》4362284320 10的地址

a------》4362284640   20的地址
b------》4362284320   10的地址

list1,list2----->4363800456
list1,list2----->4363800456

对于不可变数据类型,如果修改值,内存地址会发生改变
对于可变数据类型,如果修改值【容器中的元素】。内存地址不会发生改变
1.2copy和=
1.=
a.单列表
list1 = [1,2,3]
list2 = list1
print(list1,list2)
list1[1] = 100
print(list1,list2)


b.嵌套列表
list1 = [[1,2,3],[4,5]]
list2 = list1
print(list1,list2)
list1[1][1] = 100
print(list1,list2)
print(id(list1),id(list2))

2.copy()
a.单列表copy
list1 = [1,2,3]
list2 = list1.copy()
print(list1,list2)
list1[1] = 100
print(list1,list2)
print(id(list1),id(list2))

b.嵌套copy
list1 = [[1,2,3],[4,5]]
list2 = list1.copy()
print(list1,list2)
list1[1][1] = 100
print(list1,list2)
print(id(list1),id(list2))


总结:前提:不管是基层列表 ,都更改最里层的数据
=:不管是单层列表还是嵌套列表,只要其中一个更改,另一个随着更改
copy:对于单层列表,其中一个更改,另一个不受影响
    对于嵌套列表,其中一个更改,另一个随着更改
copy只拷贝最外层
1.3浅拷贝和深拷贝【面试题】

Python提供了copy模块来复制一个对象。copy模块提供了浅复制和深复制两种方式,它们的使用方式相同,但是执行的效果有一定的差异

浅拷贝:是对于一个对象的顶层拷贝,通俗的理解是:拷贝了引用,并没有拷贝内容

深拷贝:是对于一个对象所有层次的递归拷贝

import  copy
copy.copy()表示浅拷贝,copy.deepcopy()表示深拷贝

1.浅拷贝
a.单层浅拷贝
list1 = [1,2,3]
list2 = copy.copy(list1)
print(list1,list2)
list1[1] = 100
print(list1,list2)
print(id(list1),id(list2))

b.嵌套浅拷贝
list1 = [[1,2,3],[4,5]]
list2 = copy.copy(list1)
print(list1,list2)
list1[1][1] = 100
print(list1,list2)
print(id(list1),id(list2))

2.深拷贝
a.单层深拷贝
list1 = [1,2,3]
list2 = copy.deepcopy(list1)
print(list1,list2)
list1[1] = 100
print(list1,list2)
print(id(list1),id(list2))

b.嵌套深拷贝
list1 = [[1,2,3],[4,5]]
list2 = copy.deepcopy(list1)
print(list1,list2)
list1[1][1] = 100
print(list1,list2)
print(id(list1),id(list2))

总结:
copy.copy(列表)/列表.copy():对于单层列表,其中一个更改,另一个不受影响
                      对于嵌套列表,其中一个更改,另一个随着更改
           
copy.deepcopy(列表):对于所有列表,其中一个更改,另一个不受影响

2.列表推导式

列表推导式,就是指的轻量级循环创建列表


语法:[元素的规律 for循环 if条件]
作用:简化代码
特点:本质生成一个列表

1.生成列表[1,2,3,4....9]
list(x)将容器x转化为列表
list1 = list(range(1,10))
print(list1)

2.生成列表[1,4,9,16....81]
#方式一
list21 = []
for i in range(1,10):
list21.append(i ** 2)
print(list21)

#方式二
list22 = [i ** 2 for i in range(1,10)]
print(list22)
print(type(list22))

3.生成列表[1,9,25,49,81]
#方式一
list31 = []
for i in range(1,10):
if i % 2 == 1:
    list31.append(i ** 2)
print(list31)

#方式二
list32 = [i ** 2 for i in range(1,10) if i % 2 == 1]
print(list32)

例:生成一个列表,列表中的元素为1~30之间3的倍数
list33 = [n for n in range(1,31) if n % 3 == 0]
print(list33)

4.可以使用两个for循环
#方式一
list41 = []
for i in "ABC":
for j in "XYZ":
    list41.append(i + j)     #举例:"a" + "b" ---->"ab" 拼接
print(list41)

#方式二:在列表推导式中,平行书写的for循环实际相当于嵌套for循环
list42 = [i + j for i in "ABC" for j in "XYZ"]
print(list42)

list43 = [[i,j,k] for i in range(3) for j in range(2) for k in range(2)]
print(list43)

例:已知一个数字列表,生成一个新的列表,列表中的元素为原列表的2倍
numlist = [34,6,6,56,5]
newlist = [num * 2 for num in numlist]
print(newlist)

3.简单算法

1.1冒泡排序

排序思路:比较两个相邻的下标对应的元素,如果符合条件就交换位置(最值出现在最后位)

[12,9,13,7,5]----->[5,7,9,12,13]

0       1       2       3         4

12       9       13       7         5

比较的轮数       参与比较的下标         每一轮比较的次数     结果
第0轮           0-1 1-2 2-3 3-4         4           得到了最大值
第1轮           0-1 1-2 2-3             3           得到了第二大值
第2轮           0-1 1-2                 2
第3轮           0-1                       1

0   3
1   2
2   1
3   0

规律:
a.使用嵌套循环:for循环
b.外层循环:控制比较的轮数
  内层循环:控制每一轮比较的次数兼顾参与比较的下标

c.外层循环的取值范围:0~3---》0 ~ len - 2---->range(0,len - 1)--->range(len - 1) i
  内层循环的取值范围:0 ~ (3 - i)---->0~(len - 2 - i)---->range(len - 1 - i) j

list1 = [45,2,100,56,6,55,70]

for i in range(len(list1) - 1):
for j in range(len(list1) - 1 - i):
    #比较:如果下标小的元素 > 下标大的元素,则交换位置.升序
    if list1[j] > list1[j + 1]:
        list1[j],list1[j + 1] = list1[j + 1],list1[j]
print(list1)
1.2选择排序

排序思路:固定一个下标,然后拿这个下标对应的值依次和后面的元素进行比较,最值出现在头角标位置上

[12,9,13,7,5]----->[5,7,9,12,13]

0       1       2       3         4

12       9       13       7         5

比较的轮数       参与比较的下标             每一轮比较的次数     结果
第0轮           0-1 0-2 0-3 0-4               4           得到了最小值【最左边】
第1轮           1-2 1-3 1-4                   3           。。。。
第2轮           2-3 2-4                       2
第3轮           3-4                           1

规律:
a.使用嵌套循环:for循环
b.外层循环:控制比较的轮数
  内层循环:控制每一轮比较的次数兼顾参与比较的下标

c.外层循环的取值范围:0~3---》0 ~ len - 2---->range(0,len - 1)--->range(len - 1) i
  内层循环的取值范围:i + 1 ~ 4---->i + 1 ~ len - 1---->range(i + 1,len) j

d.参与比较的下标:i 和 j

list1 = [45,2,100,56,6,55,70]

#选择排序:升序
for i in range(len(list1) - 1):
for j in range(i + 1,len(list1)):
    if list1[i] > list1[j]:
        list1[i],list1[j] = list1[j],list1[i]

print(list1)
1.3二分法查找

查找思路:将待查找的元素与中间下标对应的元素比较,如果大于中间下标对应的元素,则去右半部分查找

注意:前提是列表是有序(升序或者降序)的,通过折半来缩小查找范围,提高查找效率

#二分法查找:列表必须是有序的

list1 = [45,65,6,7,100,45,65,47]
list1.sort()  #升序
print(list1)

#待查找的元素
key = 45

#初始值
left = 0
right = len(list1) - 1

#说明:当left == right,还未找到元素,则说明不存在
while left <= right:
middle = (left + right) // 2

#左半部分
if list1[middle] > key:
    #给right重新赋值
    right = middle - 1
#右半部分
elif list1[middle] < key:
    #给left重新赋值
    left = middle + 1
#找到了
else:
    print("待查找元素的下标为:%d" % (middle))
    #如果查找到,则可以提前结束循环
    break
else:
print("待查找元素不存在")
上一篇:LeetCode 23 链表 Merge k Sorted Lists


下一篇:OpenCV读写视频文件解析(二)