返回博客

09. list 与 tuple:有序集合的使用

09. list 与 tuple:有序集合的使用

第九篇:list 与 tuple——有序集合的增删改查、切片、排序详解

前言

Python 提供了多种内置数据结构,其中**列表(list)和元组(tuple)**是最常用的有序集合。本文将从零开始全面讲解 list 和 tuple 的各种操作:增删改查、切片、排序方法,以及两者之间的核心区别和选择策略。

列表(list)基础

什么是列表?

列表是 Python 中最灵活的数据结构之一,可以存储任意类型的元素,支持动态扩容。

# 创建空列表
empty = []
empty_alt = list()

# 创建含初始元素的列表
fruits = ["apple", "banana", "cherry"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True, None]

# 列表可以嵌套
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

len() 函数

print(len([1, 2, 3]))         # 3
print(len([]))                # 0
print(len([[1, 2], [3, 4]]))  # 2

list 的基本操作

索引访问

fruits = ["apple", "banana", "cherry", "date"]

# 正向索引从 0 开始
print(fruits[0])   # apple
print(fruits[2])   # cherry

# 负向索引从 -1 开始
print(fruits[-1])  # date
print(fruits[-2])  # cherry

# ❌ 索引越界抛出异常
# print(fruits[10])  # IndexError!

切片操作

nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 基本切片 [start:end](左闭右开)
print(nums[2:5])       # [2, 3, 4]
print(nums[:3])        # [0, 1, 2]
print(nums[7:])        # [7, 8, 9]

# 步长参数 [start:end:step]
print(nums[::2])       # [0, 2, 4, 6, 8]
print(nums[1::2])      # [1, 3, 5, 7, 9]

# 反转列表
print(nums[::-1])      # [9, 8, 7, ..., 0]

# 用切片复制列表
copy = nums[:]         # 浅拷贝

添加元素

fruits = ["apple", "banana"]

# append():末尾添加单个元素
fruits.append("cherry")

# insert():指定位置插入
fruits.insert(0, "avocado")

# extend():批量追加多个元素
fruits.extend(["date", "elderberry"])

删除元素

fruits = ["apple", "banana", "cherry", "date"]

# remove():按值删除第一个匹配项
fruits.remove("banana")

# pop():按索引删除并返回值
last = fruits.pop()      # 弹出最后一个
first = fruits.pop(0)    # 弹出索引 0

# del:按索引或切片删除
del fruits[0]
del fruits[1:3]          # 删除多个

修改元素

fruits = ["apple", "banana", "cherry"]
fruits[1] = "blueberry"
fruits[0:2] = ["apricot", "blackberry"]

查找与计数

scores = [85, 92, 85, 78, 92, 85]

print(scores.index(92))     # 1 — 第一次出现的位置
print(scores.count(85))     # 3
print(85 in scores)         # True
print(100 not in scores)    # True

列表排序

sort() 方法 vs sorted() 函数

特性 list.sort() sorted(iterable)
返回值 None(原地排序) 新列表(原列表不变)
适用对象 仅列表 任何可迭代对象
# sort() — 原地排序
nums = [3, 1, 4, 1, 5, 9, 2, 6]
nums.sort()
print(nums)  # [1, 1, 2, 3, 4, 5, 6, 9]

# sorted() — 返回新列表
original = [3, 1, 4, 1, 5, 9, 2, 6]
new_nums = sorted(original)
print(new_nums)      # [1, 1, 2, 3, 4, 5, 6, 9]
print(original)      # 原列表不变

reverse 参数

nums.sort(reverse=True)  # 逆序
result = sorted(names, reverse=True)

key 参数:自定义排序规则

# 按字符串长度排序
words = ["banana", "pie", "apple", "kiwi"]
words.sort(key=len)
# ['pie', 'kiwi', 'apple', 'banana']

# 忽略大小写排序
cities = ["beijing", "Beijing", "SHANGHAI"]
cities.sort(key=str.lower)

# 按字典字段排序
students = [{"name": "A", "score": 92}, {"name": "B", "score": 88}]
students.sort(key=lambda x: x["score"])

稳定性

Python 排序是稳定排序——相等元素的相对顺序不变:

pairs = [("Alice", 3), ("Bob", 1), ("Charlie", 3)]
pairs.sort(key=lambda x: x[1])
# Alice 在 Charlie 前,排序后仍保持此顺序

列表推导式

# 基本形式
squares = [x ** 2 for x in range(1, 6)]
print(squares)  # [1, 4, 9, 16, 25]

# 带条件的推导式
evens = [x for x in range(1, 11) if x % 2 == 0]
print(evens)  # [2, 4, 6, 8, 10]

# 双重循环
colors = ["red", "green", "blue"]
sizes = ["S", "M", "L"]
products = [f"{color}-{size}" for color in colors for size in sizes]

# 列表推导式通常比 append 快 20%-40%

元组(tuple)

创建元组

empty = ()
one_element = (42,)       # 注意逗号!
multi = (1, 2, 3)
mixed = (1, "hello", 3.14)
tup = 1, 2, 3             # 隐式元组

不可变性

point = (10, 20)
# point[0] = 15    # TypeError! 不能修改
# point.append(...)  # AttributeError!

# 但元组中可以包含可变对象
container = ([1, 2], [3, 4])
container[0].append(5)  # ✅ 允许!列表本身可变
print(container)        # ([1, 2, 5], [3, 4])

应用场景

# 场景一:返回多个值
def divide(a, b):
    return a // b, a % b
q, r = divide(10, 3)

# 场景二:作为字典键(不可变保证哈希安全)
location_map = {("北京", 39.9, 116.4): "首都机场"}

# 场景三:保护数据不被修改
RGB_COLOR = (255, 99, 71)
data_tuple = tuple(data_list)  # 列表转元组

list vs tuple 对比

特性 list tuple
语法 [1, 2, 3] (1, 2, 3)
可变性 ✅ 可变 ❌ 不可变
内存 略高(预留空间) 略低(固定大小)
速度 略慢 略快(优化更好)
安全性 低 高
可哈希 ❌ 不能作为 dict 键 ✅ 可以作为 dict 键
适用 频繁增删改 固定不变的数据

何时用哪个?

# ✅ list:待办事项会变化
todo_items = []                  

# ✅ tuple:颜色坐标不会变
RGB_COLOR = (255, 99, 71)
COORDINATE = (39.9, 116.4)
DATE = (2026, 9, 9)

# namedtuple 获得更清晰的语义
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(10, 20)
print(p.x)  # 10

实战示例

成绩管理

scores = []
while True:
    name = input("学生姓名(quit 退出):")
    if name == "quit": break
    score = int(input("分数:"))
    scores.append((name, score))

scores.sort(key=lambda x: x[1], reverse=True)
for i, (name, score) in enumerate(scores, 1):
    print(f"{i}. {name}: {score} 分")
avg = sum(s for _, s in scores) / len(scores)
print(f"平均分:{avg:.1f}")

去重并保持顺序

def unique_ordered(items):
    seen = set()
    result = []
    for item in items:
        if item not in seen:
            seen.add(item)
            result.append(item)
    return result

print(unique_ordered([3, 1, 4, 1, 5, 9, 2, 6, 5]))
# [3, 1, 4, 5, 9, 2, 6]

矩阵运算

rows, cols = 3, 4
matrix = [[0 for _ in range(cols)] for _ in range(rows)]
for i in range(min(rows, cols)):
    matrix[i][i] = 1
transposed = [[matrix[j][i] for j in range(rows)] for i in range(cols)]

总结

本文涵盖了 list 和 tuple 的核心知识:

  1. list 基础 — 创建、len()、索引访问
  2. 增删改查 — append/insert/extend/remove/pop/del/index/count
  3. 切片 — [start:end:step]、反转、浅拷贝
  4. 排序 — sort() vs sorted(),reverse 和 key 参数
  5. 列表推导式 — 简洁高效的创建方式
  6. tuple 不可变性 — 适合保护数据和作为 dict 键
  7. list vs tuple — 可变用 list,不可变用 tuple
  8. 实用技巧 — 解包赋值、namedtuple、矩阵操作

下一篇文章将深入讲解 dict 与 set:字典的键值对操作与集合的去重特性。


本文是 Python 教程系列的第九篇。