List and Tuple Tutorial 2

难度: 1

时长: 45 min


成员包含 in

  1. [1,2,5,7] 是否包含 2 呢?怎么实现?

  2. 文件属性 Permissions = "rw",检查其是否可写,是否可执行?

  3. 检查输入用户名是否为合法 users = ['mlh', 'foo', 'bar']

for ... in 循环

打印每个成员

最简单的情况是不需要写索引的:

a = [1,2,3,4,5,6]
for each in a:
    print(each)

案例2: 将偶数位置的成员值乘 10

写法1: 人工维持 index 自增

for ... in 循环 + 人工维持 index 自增

a = [1,2,3,4,5,6]
index = 0
for each in a:
    if index % 2 == 0:
        a[index] = each *10
    index += 1
    
print(a)

写法2: 经典写法 range(len)

此方法需要提前知道 a 的长度:

a = [1,2,3,4,5,6]
for index in range(len(a)):
    if index % 2 == 0:
        a[index] = each *10
print(a)

下面的 enumerate() 写法更简洁。

写法3: enumerate()

让临时索引不那么可见:

a = [1,2,3,4,5,6]
for index, each in enumerate(a):
    if index % 2 == 0:
        a[index] = each *10

好处是代码短了2行,而且是容易出错的两行。一个是初始化,另一个是 index 的自增。这两个属于固定动作,现在用 enumerate() 给自动化了。

也可以很紧凑地用下面的代码:

a[::2] = [0] * 3

zip() 用法

zip() 和 enumerate() 用法是类似的,不同的是将序号换成了一个列表。例如,并行打印两个列表中的名字与年龄:

name = ['Tom', 'Alice', 'Bob']
age = [30, 42, 35]
for name, age in zip(name, age):
    print(name, age)

列表推导式 (List Comprehension)

传统写法示例:

# 传统方法
squares = []
for x in range(10):
    squares.append(x**2)

更简洁的列表创建方式:

# 列表推导式
squares = [x**2 for x in range(10)]

示例:将偶数位置的成员值乘 10

# 传统方法
a = [1,2,3,4,5,6]
for index, each in enumerate(a):
    if index % 2 == 0:
        a[index] = each * 10

简洁写法:

# 列表推导式
a = [x * 10 if i % 2 == 0 else x for i, x in enumerate(a)]

列表示推导的语法特点

  • 更简洁、可读性更好

  • 性能通常优于传统循环

  • 支持条件过滤:[x for x in range(10) if x % 2 == 0]

  • 支持嵌套循环

[练习2]: List for-in 修改

题目:学生成绩处理

scores = [85, 92, 78, 96, 88, 76, 95, 89]
  1. 将不及格分数(<60)替换为60

  2. 将前3个成绩提高10%

  3. 使用enumerate()打印每个学生的序号和成绩

[答案]

列表赋值: 指向同一对象(副作用)

在仿真通信系统时,接收端的信号 recv_signal 引用了发送端发送的信号 send_signal,并做了一些修改处理,却意外地发现发送信号也发生了变化:

>>> send_signal = [1,2,3,4,5] 
>>> recv_signal = send_signal
>>> recv_signal[2]=10            #2 修改接收信号
>>> print(send_signal) 
[1, 2, 10, 4, 5]

总结哪里有问题!!! 如何解决和避免?

改法1

>>> send_signal = [1,2,3,4,5] 
>>> recv_signal = send_signal.copy()
>>> recv_signal[2]=10            #2 修改接收信号
>>> print(send_signal)  

改法2

>>> send_signal = [1,2,3,4,5] 
>>> recv_signal = send_signal[:]
>>> recv_signal[2]=10            #2 修改接收信号
>>> print(send_signal) 

以上哪个方法正确? 你还可以用 id() 探索一下这几种情况下 send_singlerecv_signal 之间的关系

综合练习

[练习3]: 列表成员查找

已知有一个列表 a,包含了一组学生的数据(姓名,学号),要求写一个程序,完成以下功能:

  1. 能够根据姓名或学号,查询到学生的完整记录并返回。

  2. 根据姓名,或者学号排序

数据样表:

a = [('张三', 1001),
    ('李四', 1002),
    ('王五', 1003),
    ('陈六', 1004),
    ...]

=========================

Input: '王五'

Output: ('王五', 1003)

思路:把每一行的记录都找出来,看每一行的第一个字段是姓名是什么是,是不是要找的名字,如果是,则打印结果。

示例: 通过学生「姓名」查找

a = [('张三', 1001),
    ('李四', 1002),
    ('王五', 1003),
    ('陈六', 1004),]

for student in a:
    print(student)
    print(student[0], student[1])
    if student[0] == '王五':
        print(student)

练习: 通过修改上面的代码,完成通过学号查找

思考:如何评价查找计算量?其计算量有多大?

[练习4]: 列表条件筛选

题目:学生信息管理系统(结合列表推导式)

students = [
    ('张三', 18, 85),
    ('李四', 19, 92), 
    ('王五', 20, 78),
    ('赵六', 18, 96)
]
  1. 使用列表推导式获取所有学生的姓名

  2. 获取年龄大于18岁的学生信息

  3. 计算平均成绩

要求: 均使用列表推导式实现,除开打印外,其他代码只能用一行。

[答案]