在Python中,列表(list)是一种非常强大且灵活的数据结构,它允许你存储和操作一系列的项目。以下是一些常见的列表操作处理,包括创建、访问、修改、添加、删除、遍历、排序和列表推导等。
1,list的相关操作示例如下:
# 空列表
empty_list = []
empty_list1 = list()
print(empty_list) # 输出 []
print(empty_list1) # 输出 []
# 初始化列表
mixed = [1, "hello", 3.14, True]
print(mixed) # 输出 [1, 'hello', 3.14, True]
# 正向索引
print(mixed[2]) # 输出 3.14
# 反向索引
print(mixed[-2]) # 输出 3.14
# 末尾添加元素
mixed.append("apple")
print(mixed) # 输出 [1, 'hello', 3.14, True, 'apple']
# 插入到指定位置
# 在Python中,list.insert(index, element) 方法用于在列表的指定位置插入一个元素。这里的 index 参数指定了新元素应该被插入的位置。
mixed.insert(3, "fruits")
print(mixed) # 输出 [1, 'hello', 3.14, 'fruits', True, 'apple']
# 使用 mixed.insert(-1, "color") 时,-1 作为索引表示列表的倒数第一个元素的位置之前,不是在列表的最后
mixed.insert(-1, "color")
print(mixed) # 输出 [1, 'hello', 3.14, 'fruits', True, 'color', 'apple']
# 合并列表,列表末尾追加多个元素
mixed.extend(['Jim', 'Jacky', 'Lucy'])
# 下面的代码将输出 [1, 'hello', 3.14, 'fruits', True, 'color', 'apple', 'Jim', 'Jacky', 'Lucy']
print(mixed)
# 按值删除,若值不存在会报错,捕捉异常
try:
mixed.remove("banana")
except ValueError:
print("valueError, not in list")
# 按索引删除
popped = mixed.pop(1) # 删除索引1的元素并返回
print(popped) # 输出 hello
print(f"before call del:{mixed}")
# 上面的代码输出 before call del:[1, 3.14, 'fruits', True, 'color', 'apple', 'Jim', 'Jacky', 'Lucy']
del mixed[0] # 删除索引0的元素
# 下面的代码输出 after call del:[3.14, 'fruits', True, 'color', 'apple', 'Jim', 'Jacky', 'Lucy']
print(f"after call del:{mixed}")
# 修改元素
mixed[-1] = "Lily"
print(mixed) # 输出 [3.14, 'fruits', True, 'color', 'apple', 'Jim', 'Jacky', 'Lily']
# 查找元素
if "lucy" in mixed:
print("lucy is in list")
else:
print("lucy is not in list")
try:
pos0 = mixed.index(3.14)
print(pos0) # 输出 0
pos1 = mixed.index('lucy')
print(pos1) # 出现异常,下面的代码不再执行
pos2 = mixed.index('Jacky')
print(pos2)
except ValueError:
print("call index occurs ValueError")
# 上面的代码输出 call index occurs ValueError
# 由于在获取lucy的索引时出现异常,所以不执行查找Jacky的索引
# 清空列表
mixed.clear() # 列表变为空列表 []
# 列表推导式
squares = [x ** 2 for x in range(10)]
print(squares) # 输出 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 排序与反转
nums = [3, 1, 4, 1, 5, 9, 2]
# 原地排序(修改原列表)
nums.sort()
print(nums) # 输出 [1, 1, 2, 3, 4, 5, 9]
nums.sort(reverse=True) # 降序排序
print(nums) # 输出 [9, 5, 4, 3, 2, 1, 1]
# 生成新排序列表,原列表不变
sorted_nums = sorted(nums)
print(nums) # 输出 [9, 5, 4, 3, 2, 1, 1]
print(sorted_nums) # 输出 [1, 1, 2, 3, 4, 5, 9]
# 反转列表
print(f"before reverse:{nums}") # 输出 before reverse:[9, 5, 4, 3, 2, 1, 1]
# 对列表本身进行逆序
nums.reverse()
print(f"call reverse,list:{nums}") # 输出 call reverse,list:[1, 1, 2, 3, 4, 5, 9]
reverse1 = nums[::-1]
print(f"call [::-1]:{reverse1}") # 输出 call [::-1]:[9, 5, 4, 3, 2, 1, 1]
# nums[::-1]并未对nums本身进行逆序
print(f"now nums:{nums}") # 输出 now nums:[1, 1, 2, 3, 4, 5, 9]
# 切片操作
nums = [0, 1, 2, 3, 4, 5]
print(nums[:4]) # 输出 [0, 1, 2, 3]
print(nums[1:4]) # 输出 [1, 2, 3](左闭右开)
print(nums[::2]) # 输出 [0, 2, 4](步长为2)
print(nums[::-1]) # 输出 [5, 4, 3, 2, 1, 0](反转列表)
# 生成偶数列表
evens = [x for x in range(10) if x % 2 == 0]
print(f"even num:{evens}") # 输出 even num:[0, 2, 4, 6, 8]
# 嵌套循环
pairs = [(x, y) for x in [1, 2] for y in [3, 4]] # [(1,3), (1,4), (2,3), (2,4)]
print(f"nest loop:{pairs}") # 输出 nest loop:[(1, 3), (1, 4), (2, 3), (2, 4)]
# 长度与统计
length = len(nums) # 列表长度
print(length) # 输出 6
count = nums.count(1) # 元素1出现的次数
print(count) # 输出 1
# 列表合并
combined = [1, 2] + [3, 4]
print(combined) # 输出 [1, 2, 3, 4]
# 生成数字列表
numbers = list(range(5))
print(numbers) # 输出 [0, 1, 2, 3, 4]
# 在Python中,列表(list)是一种可变的数据结构,可以包含多个元素,这些元素可以是数字、字符串、甚至是其他列表。
# 当我们想要复制一个列表时,有两种主要的拷贝方式:浅拷贝(shallow copy)和深拷贝(deep copy)。
import copy
# 浅拷贝:创建一个新列表,但新列表中的元素是对原列表中元素的引用。如果原列表包含可变对象,那么这些对象在新列表和原列表中共享。
# 下面的代码中,b 是 a 的一个浅拷贝。b 和 a 是两个不同的列表对象,但是 b 中的子列表 [1, 2] 和 [3, 4] 仍然是 a 中对应子列表的引用。
# 因此,如果你修改了 b 中某个子列表的内容,这个修改也会反映在 a 中对应的子列表上。
a = [[1, 2], [3, 4]]
b = a.copy() # 浅拷贝:子列表仍是引用
print(f"copy:{b}")
b[0][1] = 99
print(f"modify b check a:{a}") # 输出 modify b check a:[[1, 99], [3, 4]]
a[1][1] = 199
print(f"modify a check b:{b}") # 输出 modify a check b:[[1, 99], [3, 199]]
# 深拷贝:递归地复制原列表中的所有元素,包括任何嵌套的可变对象。新列表和原列表在内存中是完全独立的。
# 下面代码中,b 是 a 的一个深拷贝。b 和 a 是完全不同的列表对象,并且 b 中的子列表也是 a 中对应子列表的完全独立的副本。
# 因此,修改 b 中的任何元素都不会影响 a。
b = copy.deepcopy(a)
print(f"deep copy:{b}")
b[0][1] = 109
print(f"deep copy, modify b check b:{b}") # 输出 deep copy, modify b check b:[[1, 109], [3, 4]]
print(f"deep copy, modify b check a:{a}") # 输出 deep copy, modify b check a:[[1, 99], [3, 4]]
a[0][0] = 999
print(f"deep copy, modify a check a:{a}") # 输出 deep copy, modify a check a:[[999, 99], [3, 199]]
print(f"deep modify a check b:{b}") # deep modify a check b:[[1, 109], [3, 199]]
# 空列表判断:if not my_list: 比 len(my_list) == 0 更简洁。
my_list = []
# 空列表在布尔上下文中被视为 False
if not my_list:
print("empty")
else:
print("not empty")
# 上面的代码将输出 empty
2,双端队列deque
deque(双端队列)在头部和尾部插入/删除操作的时间复杂度均为 O(1),而普通列表的头部插入/删除操作时间复杂度为 O(n)。
适用于需要高频操作队列头部或尾部的场景(如队列、滑动窗口、BFS算法等)。
from collections import deque
# 初始化 deque
d = deque() # 空队列
print(d) # 输出 deque([])
d = deque([1, 2, 3])
print(d) # 输出 deque([1, 2, 3])
# 添加元素,尾部添加
d.append(4)
print(d) # 输出 deque([1, 2, 3, 4])
# 头部添加
d.appendleft(0)
print(d) # 输出 deque([0, 1, 2, 3, 4])
# 删除元素,尾部删除
d.pop()
print(d) # 输出 deque([0, 1, 2, 3])
# 头部删除
d.popleft()
print(d) # 输出 deque([1, 2, 3])
# 移动操作
# 向右循环移动1步
d.rotate(1) # 向右循环移动1步 → deque([3, 1, 2])
print(d) # 输出 deque([3, 1, 2])
# 向左循环移动1步
d.rotate(-1)
print(d) # 输出 deque([1, 2, 3])
# 向右循环移动2步
d.rotate(2)
print(d) # deque([2, 3, 1])
# 性能对比
import time
from collections import deque
def test_list(n):
lst = []
for i in range(n):
lst.insert(0, i) # 头部插入(时间复杂度 O(n))
def test_deque(n):
dq = deque()
for i in range(n):
dq.appendleft(i) # 头部插入(时间复杂度 O(1))
# 测试 10,000 次操作
start = time.time()
test_list(10_000)
print("List time:", time.time() - start) # 约 0.009秒
start = time.time()
test_deque(10_000)
print("Deque time:", time.time() - start) # 约 0.001秒
# 上面的输出如下
# List time: 0.009096384048461914
# Deque time: 0.0010247230529785156
# 限制队列最大长度
d = deque(maxlen=3) # 最多保存3个元素
d.append(1) # deque([1])
d.append(2) # deque([1, 2])
d.append(3) # deque([1, 2, 3])
print(d) # 输出 deque([1, 2, 3], maxlen=3)
# 自动移除头部
d.append(4)
print(d) # deque([2, 3, 4], maxlen=3)
# 从collections模块导入deque类,deque是一个双端队列,支持快速的从两端添加或删除元素
from collections import deque
# 导入threading模块,该模块提供了线程相关的类和函数,用于多线程编程。
import threading
dq = deque()
def worker():
# 在worker函数内部,使用一个for循环遍历从0到999的整数。
for i in range(1000):
# 将循环变量i添加到deque对象dq的末尾。由于deque是线程安全的,多个线程可以同时调用append方法而不会导致数据损坏。
dq.append(i)
# 创建一个空列表threads,用于存储将要启动的线程对象
threads = []
# 使用一个for循环来创建和启动4个线程。
for _ in range(4):
# 创建一个线程对象t,其目标函数是之前定义的worker函数。
t = threading.Thread(target=worker)
# 将新创建的线程对象t添加到threads列表中
threads.append(t)
# 启动线程t,使其开始执行worker函数
t.start()
for t in threads:
# 对每个线程调用join方法,这会阻塞当前线程(即主线程),直到被调用的线程执行完毕。这确保了主线程在所有工作线程完成之前不会继续执行。
t.join()
# 在所有线程都执行完毕后,打印deque对象dq的长度。由于每个线程都向dq中添加了1000个元素,总共有4个线程,因此dq的长度应该是4000。
print(len(dq)) # 正确输出 4000(无竞争问题)
综上,在随机访问(如 lst[500])或中间位置操作时优先使用List 在高频头尾插入/删除操作(性能关键场景)时优先使用 deque.