在遍历的过程当中,我们应当把序号以及内容都一并获取到。
很多初学者在进行列表遍历操作的时候, 最容易犯的一个错误就是, 他们往往会选择手动去维护一个计数器的变量, 目的是为了搞清楚当前正在处理的是第几个元素。
# 初级写法——手动计数fruits = ["苹果", "香蕉", "橘子", "葡萄"]
i = 0
for fruit in fruits:
print(f"第{i + 1}个水果是{fruit}")
i += 1
# 高手写法——用 enumerate()
for i, fruit in enumerate(fruits):
print(f"第{i + 1}个水果是{fruit}")
当使用枚举的方式时, 系统会同时为你自动分配“序号”以及对应的实际数值。这种做法最大的好处在于, 你再也不用通过手动添加数字来维护一个计数器了。
一、关于通过调用一个叫做 range 的函数来生成一连串数字的做法, 其中包含了有关这个函数的具体使用方法, 而在这里所讨论的是这种函数一共存在的三种具体的操作步骤。
# range(stop) — 0 到 stop-1for i in range(5):
print(i) # 0, 1, 2, 3, 4
# range(start, stop) — start 到 stop-1
for i in range(2, 7):
print(i) # 2, 3, 4, 5, 6
# range(start, stop, step) — 步长为 step
for i in range(0, 20, 3):
print(i) # 0, 3, 6, 9, 12, 15, 18
# 步长为负数——倒序
for i in range(10, 0, -2):
print(i) # 10, 8, 6, 4, 2
1.2 range 不是列表
r = range(5)print(r) # range(0, 5) —— 不是一个完整的列表
print(list(r)) # [0, 1, 2, 3, 4] —— 转成列表才能看到全部
# range 的优点:省内存!
# range(1000000) 只占几十个字节
# list(range(1000000)) 占几 MB 内存
# 判断元素是否在 range 里
print(3 in range(5)) # True
print(100 in range(5)) # False(O(1) 速度!
)
1.在具体的实际应用场景之中, 我们对于三个范围这样的概念进行了深入的探索与运用分析。
# 1. 遍历列表的索引fruits = ["苹果", "香蕉", "橘子"]
for i in range(len(fruits)):
print(f"下标{i}:{fruits[i]}")
# 2. 同时遍历两个列表
names = ["张三", "李四", "王五"]
scores = [85, 92, 78]
for i in range(len(names)):
print(f"{names[i]}:{scores[i]}分")
# 3. 倒序遍历
for i in range(len(fruits) - 1, -1, -1):
print(fruits[i]) # 橘子、香蕉、苹果
# 4. 每隔一个取一个
for i in range(0, 10, 2):
print(i) # 0, 2, 4, 6, 8
# 5. 生成列表
squares = [x ** 2 for x in range(1, 11)]
print(squares) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
二、同时拿出键和值。2.1 基本用法。
fruits = ["苹果", "香蕉", "橘子", "葡萄"]# 默认从 0 开始
for i, fruit in enumerate(fruits):
print(f"下标{i}:{fruit}")
# 指定起始编号
for i, fruit in enumerate(fruits, start=1):
print(f"第{i}个水果:{fruit}")
# enumerate 返回的是什么?
enum = enumerate(fruits)
print(enum) #
print(list(enum)) # [(0, '苹果'), (1, '香蕉'), (2, '橘子'), (3, '葡萄')]
2.2 的常见写法
# 最常用for i, item in enumerate(列表):
print(f"{i}: {item}")
# 从1开始编号
for i, item in enumerate(列表, 1):
print(f"第{i}个: {item}")
# 解包两个列表
names = ["张三", "李四", "王五", "赵六"]
scores = [85, 92, 78, 95]
for i, (name, score) in enumerate(zip(names, scores), 1):
print(f"{i}. {name}:{score}分")
三、这是一个关于给列表中的每一个元素进行编号操作的实战案例, 具体为第一个实战环节。
def show_todo_list(todos):"""显示带编号的待办事项"""
if not todos:
print(" 暂无待办事项")
return
print("\n 待办事项:")
for i, todo in enumerate(todos, 1):
print(f" {i}. {todo}")
todos = ["买牛奶", "写作业", "健身", "看书"]
show_todo_list(todos)
在进行实战2这个任务的时候, 你要做的是去查找那个元素的索引。
def find_all_index(lst, target):"""查找列表中所有匹配项的索引"""
indices = [i for i, item in enumerate(lst) if item == target]
return indices
numbers = [1, 3, 5, 3, 7, 3, 9]
print(find_all_index(numbers, 3)) # [1, 3, 5]
print(find_all_index(numbers, 10)) # []
进行实战训练之三, 其核心内容是为相关的数据打上对应的标签。
def label_data(items):"""根据条件给数据打标签"""
result = []
for i, item in enumerate(items):
label = "A" if item >= 80 else "B" if item >= 60 else "C"
result.append((i, item, label))
return result
scores = [85, 42, 73, 90, 55, 68]
labeled = label_data(scores)
for i, score, label in labeled:
print(f" 第{i+1}项:{score}分 → {label}")
进行实战环节中的第四个部分任务, 也就是生成数据报告。
def generate_report(products):"""生成商品清单报告"""
print("=" * 45)
print(f"{'序号':>4} {'商品名':<12} {'价格':>8} {'库存':>6}")
print("-" * 45)
total = 0
for i, (name, price, stock) in enumerate(products, 1):
print(f"{i:>4d} {name:<12s} ¥{price:>6.2f} {stock:>5d}件")
total += price * stock
print("=" * 45)
print(f"{'库存总值:¥':>28s}{total:.2f}")
products = [
("手机", 2999, 50),
("笔记本", 5999, 30),
("耳机", 299, 200),
("充电器", 99, 500),
]
generate_report(products)
四、zip()——同时遍历多个列表
另外, 和它关系比较近的zip这个操作方式, 在日常生活中也是经常被使用到的。
names = ["张三", "李四", "王五"]ages = [25, 30, 28]
scores = [85, 92, 78]
# 同时遍历三个列表
for name, age, score in zip(names, ages, scores):
print(f"{name}:{age}岁,{score}分")
# zip + enumerate 强强联合
for i, (name, age) in enumerate(zip(names, ages), 1):
print(f"{i}. {name}:{age}岁")
五、range 和 的内存对比
import sys# range 非常省内存
r = range(1000000)
print(f"range 对象大小:{sys.getsizeof(r)} 字节") # 48 字节
# list(range()) 很费内存
lst = list(range(1000000))
print(f"列表大小:{sys.getsizeof(lst)} 字节") # 8,000,056 字节
# enumerate 也很省
fruits = ["苹果", "香蕉", "橘子"] * 10000
e = enumerate(fruits)
print(f"enumerate 对象大小:{sys.getsizeof(e)} 字节") # 56 字节
六、总结
range()——生成数字序列range(5) → 0, 1, 2, 3, 4
range(2, 7) → 2, 3, 4, 5, 6
range(1, 10, 2)→ 1, 3, 5, 7, 9
range(5, 0, -1)→ 5, 4, 3, 2, 1
enumerate()——同时拿索引和值
for i, item in enumerate(lst): → i从0开始
for i, item in enumerate(lst, 1): → i从1开始
zip()——同时遍历多个列表
for a, b in zip(list1, list2): → 配对遍历
选型口诀:
只要下标用 range(len(lst))
只要元素用 for item in lst
下标+元素都用 enumerate(lst)
同时遍历多个用 zip(lst1, lst2)
全部都要用 enumerate(zip(lst1, lst2))
课后练习:
有一组名单还有一连串的成绩数据, 用打印输出的功能来生成一个带有编号的表格内容, 利用特定的数值范围设置从十开始倒数到一的序列过程, 借助组合匹配函数把两组信息对接起来。
字符串"a", 字符串"b", 字符串"c"
把这两个东西放在一起, 然后弄成一个字典, 这个字典的形式是 {"a": 1"b": 2"c": 3}。