1.列表部分
1.1列表的定义
# 列表:是一个数据容器,是用来容纳若干数据的
# 是一个有序的、可变的数据容器
# 有序: 元素的添加顺序和存储顺序是一致的,可以使用下标(索引)访问元素
# 可变: 列表中的元素可以做到随时的添加、删除、修改
# 注意事项:
# 理论上来说,列表中可以存储不同数据类型的元素
# 但是,在实际开发中,我们需要保证数据的类型一致
# 1. 字面量: 需要将元素写入到一对[]中
l1 = [1, 2, 3, 4, 5]
print(l1)
l2 = []
print(l2)
# 2. 通过 list() 函数,将其他的容器,转成列表
l3 = list("hello world")
print(l3)
l4 = list((1, 2, 3, 4, 5))
print(l4)
l5 = list(range(0, 20, 2))
print(l5)
1.2 列表的运算符
运算符 | 描述 | 示例 |
---|---|---|
+ | 将两个列表拼接 | [1, 2, 3, 4, 5] + [9, 8, 7, 6, 5] |
* | 将列表中的元素重复若干次 | [1, 2, 3] * 3 |
+= | 在现有值的基础上拼接 | s1 = [1, 2, 3, 4, 5] ,s1+= [9, 8, 7, 6, 5] |
*= | 在现有值的基础上重复 | s1 = [1, 2, 3] s1 *= 3 |
== | 判断两个列表是否相同 | [1, 2, 3] == [1, 2, 3] |
!= | 判断两个列表是否不同 | [1, 2, 3] != [1, 2, 3] |
> | 判断列表的大小关系 | [1, 2, 3] > [1, 1, 2] |
< | 判断列表的大小关系 | [1, 2, 3] < [1, 1, 2, 2] |
>= | 判断列表的大小关系 | [1, 2, 3] >= [1, 2, 3] |
<= | 判断列表的大小关系 | [1, 2, 3] <= [1, 2, 3] |
in | 判断一个数据是否在一个列表中包含 | 3 in [1, 2, 3] |
not in | 判断一个数据是否不在一个列表中包含 | 3 not in [1, 2, 3] |
# + : 将两个列表拼接到一起,生成一个新的列表
# * : 将一个列表中的元素,重复若干次,生成一个新的列表
# += : 将两个列表拼接到一起,生成一个新的列表,并且给自己重新赋值
# *= : 将一个列表中的元素,重复若干次,生成一个新的列表,并且给自己重新赋值
# > < >= <= == != : 进行两个列表中的元素比较的
# in : 判断一个数据,是否在一个列表中包含
# not in :
print([1, 2, 3, 4, 5] + [9, 8, 7, 6, 5])
print([1, 2, 3] * 3)
list1 = [1, 2, 3, 4, 5]
list1 += [9, 8, 7, 6, 5]
print(list1)
list2 = [1, 2, 3]
list2 *= 3
print(list2)
print([1, 2, 3, 4, 5] > [1, 1, 2, 2, 3])
print(4 in [1, 2, 3, 4, 5])
1.3 列表的索引和切片
列表中的元素是有序的,每一个元素也可以使用索引来确定位置。那么我们就可以使用索引来操作指定位的元素,使用切片来获取指定范围的元素。
索引和切片的使用,与字符串的基本一致。
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
# 索引的使用
print(list1[4])
print(list1[-6])
# 切片的使用
print(list1[2:7])
print(list1[6:1:-1])
但是列表和字符串还是不同的,列表是可变的,也就是说,可以通过索引来修改指定位置的元素
# 列表是可变的,可以通过索引,修改列表中的元素的
list1[4] = 50
print(list1)
# 也可以通过切片,修改指定范围的元素
# 在替换的时候,长度可以不相同
list1[2:6] = [0, 0, 0, 0, 0, 0]
print(list1)
1.4列表的遍历
# 遍历方式与字符串完全相同
list1 = [1, 2, 3, 4, 5, 6, 7]
# 直接遍历列表中的每一个元素
for i in list1:
print(i)
print("-*" * 30)
# 通过下标遍历
for i in range(len(list1)):
print(f"list1[{i}] = {list1[i]}")
print("-*" * 30)
for i, e in enumerate(list1):
print(f"list1[{i}] = {e}")
1.5 列表的元素操作
函数 | 描述 | 示例 |
---|---|---|
append(__object) | 添加一个元素到列表的末尾 | list1 = [1, 2, 3, 4]list1.append(5) |
insert(__index, __object) | 将一个元素添加到列表的指定下标位置 | list1 = [1, 2, 3, 4, 5] |
list1.insert(0, 100) | ||
extend(__iterable) | 添加一个容器中的元素,到当前列表的末尾,相当于 += | list1 = [1, 2, 3, 4, 5],list2.extend([10, 20, 30]) |
pop(__index) | 删除指定下标位的元素,默认是最后一位__index: 需要删除的元素的下标,默认是最后一位返回值: 刚刚被删除的元素 | list1 = [1, 2, 3, 4, 5]list1.pop()list1.pop(2) |
remove(__value) | 删除列表中的指定元素。注意事项:如果这个元素不存在,报错如果存在多个,只删除第一个 | list1 = [100, 200, 300, 100],list1.remove(100) |
clear() | 清空列表中的所有元素 | list1 = [1, 2, 3, 4, 5],list1.clear() |
index(__value, __start, __stop) | 在指定范围内查找指定元素的下标如果找不到,会报错__value: 需要查找的元素__start: 开始查找的下标,默认开始__stop: 结束查找的下标,默认结尾 | list1 = [1, 2, 3, 4, 5],list1.index(2),list1.index(2, 1, 5) |
count(__value) | 查找列表中某一个元素出现了多少次 | list1 = [1, 1, 2, 3, 4],list1.count(1) |
# 创建一个列表
list1 = []
# 增
list1.append(123)
list1.append(456)
list1.append(789)
# 增: 将一个容器中的所有元素,添加到末尾
list1.extend([1, 2, 3])
list1.extend((0, 1, 0, 1, 0))
# 增:
list1.insert(3, 100)
# 注意事项: 越界的情况,不会报错
# 如果是正向索引(正数),插入到列表的最后
# 如果是负向索引(负数),插入到列表的最前
list1.insert(-100, 999)
print(list1)
# 删除: 按照索引(下标)位去删除
# pop(_index): 删除指定下标位的元素
# _index: 需要删除的下标,默认是最后一位
# 返回值: 被删除的元素
print(list1.pop(3))
# 删除: 按照元素删除
# remove(_value): 按照元素去删除的
# 1. 如果删除的元素不存在,他会报错 ValueError
# 2. 如果元素存在多个,只会删除最开始的一个
list1.remove(0)
# 删除: 清空所有
# list1.clear()
print(list1)
# 查找元素下标
# 如果元素不存在,会报错
print(list1.index(1))
# 查找元素在列表中出现的次数
print(list1.count(1))
# # 需求: 删除所有的0
# while 0 in list1:
# list1.remove(0)
#
# print(list1)
# list2 = []
# for i in range(0, 101, 2):
# list2.append(i)
#
# print(list2)
# list2 = []
# list2.extend(range(0, 101, 2))
# print(list2)
# 需求: 查询一个列表中,某一个元素最后一次出现的下标
def last_index(l: list, e: int) -> int | None:
# 思路:
# 从后往前遍历每一个元素,和需要查找的元素进行比较
# 如果找到相同的元素了,直接返回下标
for i in range(len(l) - 1, -1, -1):
if l[i] == e:
return i
return None
list3 = [1, 2, 3, 4, 5, 5, 6, 6, 4, 3, 2, 1]
print(last_index(list3, 30))
1.6 列表的其他操作
函数 | 描述 | 示例 |
---|---|---|
max(_iterable) | 获取一个容器中的最大值 | max([1, 2, 3, 4, 5]) |
min(_iterable) | 获取一个容器中的最小值 | min([1, 2, 3, 4, 5]) |
sort(key, reverse) | 将一个列表中的元素进行从小到大的升序排序。key: 函数类型,自定义排序的依据reverse: bool类型,在排序完成之后,执行翻转操作,达到降序排列的效果 | list1 = [“hello”, “hi”, “Tom”],list1.sort(),list1.sort(reverse=True),list1.sort(key=abs),list1.sort(key=abs, reverse=True) |
reverse() | 将一个列表中的元素翻转 | list1 = [1, 2, 3, 4, 5],list1.reverse() |
copy() | 生成一个列表的深拷贝 | list1 = [1, 2, 3, 4, 5],list2 = list1.copy() |
reverse 和切片的区别:
reverse和切片都可以获取到一个翻转之后的列表,但是区别在于:
切片,是获取到一个新的列表,原来列表中的元素是不会改变的
reverse,是将列表中的元素直接翻转的
# max、min: 这个函数,并不是list独有的函数,是系统内置的函数
# max: 从一个容器中,获取到最大值
print(max([1, 2, 3, 3, 4, 4, 4, 3, 4, 2, 7, 6, 5, 4, 7, 6, 3]))
# min: 从一个容器中,获取到最小值
print(min([1, 2, 3, 3, 4, 4, 4, 3, 4, 2, 7, 6, 5, 4, 7, 6, 3]))
# 排序: sort 可以将一个列表中的元素,按照一定的大小关系,重新排列
# sort(): 默认是升序排序
# reverse: 排序之后,反转
l1 = [1, 2, 3, 3, 2, 1, 1, 2, 5, 6, 7, 8, 9, 8, 7, 6, 5, 3, 0, 1, 2]
l1.sort()
print(l1)
l1.sort(reverse=True)
print(l1)
# 翻转:
l2 = [1, 2, 3, 4, 5]
l2.reverse()
print(l2)
# reverse和切片的区别:
# 切片: 会得到一个新的列表的,原来的列表中的内容是没有变化的
# reverse: 直接修改的原来的列表
l3 = [1, 2, 3, 4, 5]
# print(l3[::-1])
# print(l3)
# l3.reverse()
# print(l3)
1.7 列表的内存分析
无论是创建了一个什么容器(字符串、列表、元组、集合、字典),都需要在堆空间中进行内存的分配,用来存储若干的元素。而容器类型的变量,只是存储的这个堆空间的内存地址。
# 创建一个列表容器
# 此时需要在堆空间开辟空间,存储 1, 2, 3, 4, 5 五个元素
# list1 只是存储的这个堆空间的内存地址
list1 = [1, 2, 3, 4, 5]
1.7.1浅拷贝
直接将一个变量中存储的内存地址,赋值给另外的一个变量,这个过程叫做“浅拷贝”。
浅拷贝不会有新的堆空间开辟,得到的两个容器类型的变量,其实存储的都是地址,指向的是相同的空间。因此修改一个容器中的数据,对另外一个都会造成影响。
# 创建一个列表容器
# 此时需要在堆空间开辟空间,存储 1, 2, 3, 4, 5 五个元素
# list1 只是存储的这个堆空间的内存地址
list1 = [1, 2, 3, 4, 5]
# 直接将 list1 中存储的内存地址,赋值给了list2
# 这就是一个浅拷贝,list2 中存储的依然是指向前面开辟的堆空间
list2 = list1
# 通过list2来修改元素
list2[2] = 30
# 然后发现list1也随之修改了,原因就是浅拷贝的问题
print(list1)
1.7.2深拷贝
在堆空间中开辟一个新的空间,将原来容器中的每一个元素拷贝到这个新的空间中。这个过程叫“深拷贝”。深拷贝会产生新的堆空间,得到的容器类型的变量,也是指向新的堆空间的地址,因此对原来的容器没有影响。
# 创建一个列表容器
# 此时需要在堆空间开辟空间,存储 1, 2, 3, 4, 5 五个元素
# list1 只是存储的这个堆空间的内存地址
list1 = [1, 2, 3, 4, 5]
# 创建一个新的空间
list2 = []
# 将list1中的元素拷贝到新的空间中
list2.extend(list1)
# 修改list2
list2[2] = 30
# list1没有修改
print(list1)
# 堆
# 现在需要开辟出空间,来存储这5个数字,是在堆上开辟的空间
# 此时的l1存储的是这块空间的内存地址
l1 = [1, 2, 3, 4, 5]
# 赋值操作,将l1的值赋值给l2
# l1中存储的是一个地址,因此这时将这个地址给了l2
# 也就是说,现在的l2也指向了堆上的那一块空间
l2 = l1
# 修改列表中的元素
# 通过l2中存储的地址,找到堆空间
# 找到堆空间之后,再通过索引,找到具体的元素的空间
# 将其修改成了30
l2[2] = 30
print(f"{l1 = }, {l2 = }")
# 在上方,将一个容器的内存地址,直接给到另外一个变量进行赋值
# 这样的操作,称为 -- 浅拷贝
# 浅拷贝,其实,只是生成了一个新的变量,用来存储地址。
# 深拷贝:
# 创建一个新的容器,将原来的容器中的元素,添加到新的容器中
# 生成的就是一个新的容器
l3 = []
l3.extend(l1)
l3[2] = 300
print(f"{l1 = }, {l3 = }")
l4 = l1.copy()
1.8 列表的高级排序
在排序的时候,调用 sort 函数,可以通过参数 key,传递一个排序的依据
实现按照指定的规则进行排序。
排序逻辑: 将每一个元素带入到 key 的函数中,用返回值作为排序的依据。
在排列元素的时候,将按照这个返回值进行排序。
eg:
l1 = ["hello", "hi", "Lily", "SanPang", "Tom", "LiHua"]
# 需求: 希望对l1进行排序,排序的依据: 按照字符串的长度
# key: 需要指定一个排序的依据,需要的是一个函数
# 逻辑: 将每一个元素带入到这个函数中,使用返回值作为排序的依据
# 定义一个函数,获取字符串的长度
l1.sort(key=len)
print(l1)
l2 = [10, 12, -11, 9, 12, -13, 10, -20]
# 需求: 希望对l2进行排序,排序的依据: 按照绝对值排序
l2.sort(key=abs)
print(l2)
def get_reverse_string(s):
return s[::-1]
l3 = ["hello", "abc", "world", "lalala"]
# 需求: 希望对l3进行排序,排序的依据: 按照最后一个字母进行排序,如果相同,比较前面的一位字母
# l3.sort(key=lambda x: x[::-1])
l3.sort(key=get_reverse_string)
print(l3)
1.9 系统内置的高阶函数
高阶函数:如果一个函数的参数或者返回值,是另外一个函数。那么这样的函数就是高阶函数。
函数 | 说明 | 示例 |
---|---|---|
max(_iterable, key) | 按照指定的规则,获取到一个列表中的最大值。 key: 指定的规则,将每一个元素带入到这个函数中,用返回值作为大小比较的依据。 | list1 = [1, -2, 3, -4] |
max(list1, key=abs),min(_iterable, key) | 按照指定的规则,获取到一个列表中的最小值。key: 指定的规则,将每一个元素带入到这个函数中,用返回值作为大小比较的依据。 | list1 = [1, -2, 3, -4] |
min(list1, key=abs),sorted(_iterable, key, reverse) | 将一个容器中的元素进行生序排序,并返回升序排序之后的新的容器。key: 排序的依据reverse: 排序之后是否需要翻转 | list1 = [1, 2, -3, -4, 5] |
sorted(list1),sorted(list1, key=abs),filter(function, _iterable) | 过滤,保留下来满足条件的数据,过滤掉不满足条件的数据function: 是一个判断函数,参数是每一个元素,返回值是bool类型_iterable: 需要过滤的容器是谁 | l2 = [89, 79, 88, 59, 58, 90, 66, 65, 55, 100] |
res2 = list(filter(lambda x: x < 60, l2))map(function, _iterable) | 映射,将容器中的每一个元素,替换成其他的元素function: 提供一个映射函数,接收容器中的每一个元素,返回替代值 | l3 = [“xiaoming”, “lily”, “lucy”, “uncle wang”],res4 = list(map(lambda x: x.upper(), l3)) |
eg:
# sorted: 对一个列表进行排序,但是不会对列表本身产生影响,而是返回一个排序之后的新的列表
# 如果不想改变列表中的元素的顺序,就使用sorted
# 如果想要改变列表中的元素的顺序,就使用liebiao.sort
l1 = [1, 3, 5, 7, 9, -2, -4, -6, -8, -10]
res1 = sorted(l1, key=abs, reverse=True)
print(res1)
# max、min
# key: 设置一个比较的依据,逻辑是将每一个元素,带入到key的函数中来,使用返回值进行比较
# 需求: 找到一个列表中的绝对值最大的数字
print(max(l1, key=abs))
# 需求: 找到一个列表中的绝对值最小的数字
print(min(l1, key=abs))
# filter: 过滤,保留下来满足条件的数据,过滤掉不满足条件的数据
# 第一个参数: 是一个判断函数,参数是每一个元素,返回值是bool类型
# 第二个参数: 需要过滤的容器是谁
# 返回值: 是一个 filter object,如果需要转成列表的话,只需要使用 list()
l2 = [89, 79, 88, 59, 58, 90, 66, 65, 55, 100]
# 需求: 需要找到所有的不及格的成绩
res2 = list(filter(lambda x: x < 60, l2))
print(res2)
# 需求: 找到一个字符串中所以的数字
s1 = "hello123world456abc789"
res3 = list(filter(lambda x: x.isdigit(), s1))
print("".join(res3))
# map: 映射,将容器中的每一个元素,替换成其他的元素
# 提供一个映射函数,接收容器中的每一个元素,返回替代值
l3 = ["xiaoming", "lily", "lucy", "uncle wang"]
# 需求: 需要将每一个字符串,都换成大写
res4 = list(map(lambda x: x.upper(), l3))
print(res4)
1.10列表推导式
目的: 为了创建一个新的列表,在新的列表创建的时候,可以根据一个已有的序列,对其中的元素进行映射、过滤
映射: [映射的操作 for 迭代队列 in 序列]
过滤: [映射的操作 for 迭代队列 in 序列 if 过滤条件]
# 列表推导式
# 目的: 为了创建一个新的列表,在新的列表创建的时候,可以根据一个已有的序列,对其中的元素进行映射、过滤
# 映射: [映射的操作 for 迭代队列 in 序列]
# 过滤: [映射的操作 for 迭代队列 in 序列 if 过滤条件]
# 需求: 构建一个新的列表,新的列表中的元素,是l1中的每一个元素的值 x2
l1 = [10, 20, 30, 40, 50]
# 使用列表推导式
l2 = [i * 2 for i in l1]
print(l2)
# 需求: 有一个列表,存储的都是数字
# 需要将他们拼接成一个字符串,使用-分隔
# "10-20-30-40-50-60"
numbers = [10, 20, 30, 40, 50, 60]
numbers2 = [str(n) for n in numbers]
print("-".join(numbers2))
# 需求: 有一个纯数字的列表,其中存储的是成绩
# 将所有的不及格的成绩提取到一个新的列表中
scores = [78, 55, 67, 45, 98, 50, 66]
scores2 = [s for s in scores if s < 60]
print(f"{scores2 = }")
# 需求: 将所有的及格成绩,拼接成一个字符串,使用逗号分隔
print(",".join([str(s) for s in scores if s >= 60]))
# 需求: There is no denying that successful business lies in a healthy body and mind
# 提取这句话中包含 i 的单词
line = "There is no denying that successful business lies in a healthy body and mind"
words = line.split()
res = [x for x in words if 'i' in x]
print(res)
# #
# res1 = []
# for i in l1:
# res1.append(i * 2)
# print(f"{res1 = }")
#
# #
# res2 = list(map(lambda x: x * 2, l1))
# print(f"{res2 = }")