北京大学mooc《实用python程序设计》第六章 笔记及测试答案
第六章 列表
第一节 列表的操作
列表的增删和修改
- 列表可以增删元素,列表元素可以修改,列表元素可以使任何类型
empty=[] #表示空表
list1=['Pku','Huawei',1997,2000];
list[1]=100 #列表元素可以赋值
print(list1) #>>['Pku',100,1997,2000]
del list1[2] #删除元素
print(list1) #>>['Pku',100,2000]
list1+=[100,110] #添加另一列的元素100和110,在list1原地添加,没有新建一个列表
list1.append(200) #添加元素200,append用于添加单个元素
print(list1) #>>['Pku',100,2000,100,110,200]
list1.append(['ok',123]) #添加单个元素
print(list1) #>>['Pku',100,2000,100,110,200,['ok',123]]
a=['a','b','c']
n=[1,2,3]
x=[a,n] #a若变,x也变
a[0]=1
print(x) #>>[[1,'b','c'],[1,2,3]]
print(x[0]) #>>[1,'b','c']
print(x[0][1]) #>>b
*课外笔记
在 Python 中,列表(list)是一种可变序列,支持元素的增删和修改。以下是操作列表时需要注意的事项:
1. 增加元素
append()
: 在列表末尾添加单个元素。
注意:
append()
只能添加一个元素,若添加的是列表,整个列表会成为原列表的一个元素。lst = [1, 2, 3] lst.append(4) # lst 变为 [1, 2, 3, 4] lst.append([5, 6]) # lst 变为 [1, 2, 3, 4, [5, 6]]
extend()
: 在列表末尾添加多个元素(通常为可迭代对象)。
注意:
extend()
会将可迭代对象的元素逐个添加到列表中,而不是作为一个整体。lst = [1, 2, 3] lst.extend([4, 5]) # lst 变为 [1, 2, 3, 4, 5]
insert()
: 在指定位置插入元素。
注意:插入位置超出列表长度时,元素会添加到末尾。
lst = [1, 2, 3] lst.insert(1, 1.5) # lst 变为 [1, 1.5, 2, 3]
2. 删除元素
remove()
: 删除列表中第一个匹配的元素。
注意:若元素不存在,会抛出
ValueError
。lst = [1, 2, 3, 2] lst.remove(2) # lst 变为 [1, 3, 2]
pop()
: 删除并返回指定位置的元素,默认为最后一个元素。
注意:若索引超出范围,会抛出
IndexError
。lst = [1, 2, 3] lst.pop(1) # 返回 2,lst 变为 [1, 3]
del
: 删除指定位置的元素或切片。lst = [1, 2, 3, 4] del lst[1] # lst 变为 [1, 3, 4] del lst[1:3] # lst 变为 [1]
注意:
del
可以删除整个列表或部分元素。lst = [1, 2, 3, 4] del lst[1] # lst 变为 [1, 3, 4] del lst[1:3] # lst 变为 [1]
clear()
: 清空列表。
注意:列表变为空列表,但对象仍存在。
lst = [1, 2, 3] lst.clear() # lst 变为 []
3. 修改元素
直接赋值: 通过索引修改元素。
注意:索引超出范围会抛出
IndexError
。lst = [1, 2, 3] lst[1] = 20 # lst 变为 [1, 20, 3]
切片赋值: 通过切片修改多个元素。
注意:切片赋值可以替换多个元素,甚至改变列表长度。
lst = [1, 2, 3, 4] lst[1:3] = [20, 30] # lst 变为 [1, 20, 30, 4] lst[1:3] = [200] # lst 变为 [1, 200, 4]
4. 其他注意事项
索引和切片: 索引从 0 开始,切片左闭右开。
列表复制: 直接赋值会共享引用,修改一个会影响另一个。使用
copy()
或list()
创建新列表。列表推导式: 可以简洁地创建或修改列表。
lst = [1, 2, 3] new_lst = lst # 共享引用 new_lst[0] = 100 # lst 也变为 [100, 2, 3] new_lst = lst.copy() # 创建新列表 new_lst[0] = 200 # lst 仍为 [100, 2, 3]
性能: 在列表开头插入或删除元素效率较低,建议在末尾操作。
列表相加
- 列表相加可以得到新的列表
a=[1,2,3,4]
b=[5.6]
c=a+b
print(c) #>>[1,2,3,4,5,6]
a[0]=100
print(c) #>>[1,2,3,4,5,6]
在 Python 中,列表相加(
+
操作符)会将两个列表合并为一个新列表。以下是列表相加时需要注意的事项:
1. 列表相加的行为
使用
+
操作符时,会创建一个新的列表,并将两个列表的元素按顺序合并。原列表不会被修改。
lst1 = [1, 2, 3] lst2 = [4, 5, 6] result = lst1 + lst2 # result 为 [1, 2, 3, 4, 5, 6]
2. 注意事项
(1)性能问题
列表相加会创建一个新列表,并将所有元素复制到新列表中。如果列表很大,相加操作可能会消耗较多内存和时间。
如果需要频繁合并列表,建议使用
extend()
或itertools.chain()
,它们更高效。# 使用 extend() 修改原列表 lst1 = [1, 2, 3] lst2 = [4, 5, 6] lst1.extend(lst2) # lst1 变为 [1, 2, 3, 4, 5, 6] # 使用 itertools.chain() 生成迭代器 import itertools lst1 = [1, 2, 3] lst2 = [4, 5, 6] result = list(itertools.chain(lst1, lst2)) # result 为 [1, 2, 3, 4, 5, 6]
(2)列表与不可迭代对象相加
列表只能与可迭代对象(如列表、元组、字符串等)相加。如果尝试与非可迭代对象(如整数、浮点数等)相加,会抛出
TypeError
。lst1 = [1, 2, 3] lst2 = 4 # 整数,不可迭代 result = lst1 + lst2 # TypeError: can only concatenate list (not "int") to list
(3)嵌套列表相加
如果列表中的元素是列表(嵌套列表),相加时会保留嵌套结构。
lst1 = [[1, 2], [3, 4]] lst2 = [[5, 6], [7, 8]] result = lst1 + lst2 # result 为 [[1, 2], [3, 4], [5, 6], [7, 8]]
(4)列表与字符串相加
列表可以与字符串相加,但字符串会被拆分为单个字符并作为列表元素添加。
lst1 = [1, 2, 3] lst2 = "hello" result = lst1 + lst2 # result 为 [1, 2, 3, 'h', 'e', 'l', 'l', 'o'] lst1 = [1, 2, 3] lst2 = “你好” result = lst1 + lst2 # result 为 [1, 2, 3, 'h', 'e', 'l', 'l', 'o']
(5)原地修改与新建列表
列表相加会创建新列表,原列表不会被修改。如果需要原地修改列表,可以使用
extend()
。lst1 = [1, 2, 3] lst2 = [4, 5, 6] result = lst1 + lst2 # result 为新列表,lst1 和 lst2 不变 lst1.extend(lst2) # lst1 被修改为 [1, 2, 3, 4, 5, 6]
3. 替代方案
(1)
extend()
用于将一个列表的元素添加到另一个列表中,原地修改列表。
lst1 = [1, 2, 3] lst2 = [4, 5, 6] lst1.extend(lst2) # lst1 变为 [1, 2, 3, 4, 5, 6]
(2)
itertools.chain()
用于高效合并多个可迭代对象,返回一个迭代器。
import itertools lst1 = [1, 2, 3] lst2 = [4, 5, 6] result = list(itertools.chain(lst1, lst2)) # result 为 [1, 2, 3, 4, 5, 6]
(3)'*
解包操作符
用于合并多个列表,语法简洁。
lst1 = [1, 2, 3] lst2 = [4, 5, 6] result = [*lst1, *lst2] # result 为 [1, 2, 3, 4, 5, 6]
4. 总结
列表相加(
+
)会创建新列表,适合少量数据合并。如果需要高效合并列表,建议使用
extend()
或itertools.chain()
。注意列表相加时操作对象的类型,避免与非可迭代对象相加导致错误。
列表和+=号
b=a=[1,2]
a+=[3] #b和a指向相同的地方,在a末尾添加元素,b也受影响
print(a,b) #>>[1,2,3] [1,2,3]
a=a+[4,5] #对a重复赋值,不会影响到b
print(a) #>>[1,2,3,4,5]
print(b) #>>[1,2,3]
在 Python 中,
+=
操作符用于列表时,行为与extend()
类似,但有一些细节需要注意。以下是关于列表和+=
操作符的详细说明:
1.
+=
的基本行为
+=
操作符会原地修改列表,将右侧的可迭代对象的元素逐个添加到列表中。与
extend()
类似,但语法更简洁。lst = [1, 2, 3] lst += [4, 5, 6] # lst 变为 [1, 2, 3, 4, 5, 6]
2. 注意事项
(1)原地修改
+=
会直接修改原列表,而不是创建一个新列表。如果列表被多个变量引用,所有引用都会反映修改。
lst1 = [1, 2, 3] lst2 = lst1 # lst2 和 lst1 引用同一个列表 lst1 += [4, 5, 6] # lst1 和 lst2 都变为 [1, 2, 3, 4, 5, 6]
(2)与非列表对象相加
+=
的右侧必须是可迭代对象(如列表、元组、字符串等),否则会抛出TypeError
。lst = [1, 2, 3] lst += "hello" # lst 变为 [1, 2, 3, 'h', 'e', 'l', 'l', 'o'] lst += 4 # TypeError: 'int' object is not iterable
(3)与
+
的区别
+
操作符会创建一个新列表,而+=
会原地修改列表。如果对不可变对象(如元组)使用
+=
,会创建一个新对象。# 列表(可变对象) lst1 = [1, 2, 3] lst2 = lst1 + [4, 5, 6] # lst1 不变,lst2 为新列表 [1, 2, 3, 4, 5, 6] lst1 += [4, 5, 6] # lst1 被修改为 [1, 2, 3, 4, 5, 6] # 元组(不可变对象) tup = (1, 2, 3) tup += (4, 5, 6) # tup 被重新赋值为新元组 (1, 2, 3, 4, 5, 6)
(4)性能
+=
是原地操作,比+
更高效,尤其是在处理大列表时。如果需要频繁合并列表,推荐使用
+=
或extend()
。
3. 与
extend()
的区别
+=
和extend()
的行为几乎相同,但+=
更简洁。
extend()
是一个方法调用,而+=
是一个操作符。# 使用 extend() lst = [1, 2, 3] lst.extend([4, 5, 6]) # lst 变为 [1, 2, 3, 4, 5, 6] # 使用 += lst = [1, 2, 3] lst += [4, 5, 6] # lst 变为 [1, 2, 3, 4, 5, 6]
4. 与
append()
的区别
append()
将整个对象作为单个元素添加到列表末尾,而+=
会将可迭代对象的元素逐个添加。# 使用 append() lst = [1, 2, 3] lst.append([4, 5, 6]) # lst 变为 [1, 2, 3, [4, 5, 6]] # 使用 += lst = [1, 2, 3] lst += [4, 5, 6] # lst 变为 [1, 2, 3, 4, 5, 6]
5. 总结
+=
是原地操作,直接修改原列表,适合需要修改原列表的场景。
+=
的右侧必须是可迭代对象,否则会抛出TypeError
。与
+
相比,+=
更高效,尤其是在处理大列表时。如果需要将整个对象作为单个元素添加,应使用
append()
而不是+=
。# 示例 lst = [1, 2, 3] lst += [4, 5, 6] # lst 变为 [1, 2, 3, 4, 5, 6] lst.append([7, 8, 9]) # lst 变为 [1, 2, 3, 4, 5, 6, [7, 8, 9]]
列表的乘法
print([Ture]*3) #>>[Ture,True,True]
a=[1,2]
b=a*3
print(b) #>>[1,2,1,2,1,2]
print([a*3]) #>>[[1,2,1,2,1,2]]
c=[a]*3
print(c) #>>[[1,2],[1,2],[1,2]]
a.append(3)
print(c) #>>[[1,2,3],[1,2,3],[1,2,3]]
print(b) #>>[1,2,1,2,1,2]
在 Python 中,列表的乘法(
*
操作符)用于重复列表中的元素。以下是关于列表乘法的详细说明和注意事项:
1. 列表乘法的基本行为
使用
*
操作符可以将列表中的元素重复指定次数,生成一个新列表。原列表不会被修改。
lst = [1, 2, 3] result = lst * 3 # result 为 [1, 2, 3, 1, 2, 3, 1, 2, 3]
2. 注意事项
(1)嵌套列表的重复
如果列表中的元素是可变对象(如列表、字典等),重复操作会创建对这些对象的引用,而不是独立的副本。
修改其中一个元素会影响所有重复的元素。
lst = [[1, 2]] * 3 # lst 为 [[1, 2], [1, 2], [1, 2]] lst[0][0] = 100 # lst 变为 [[100, 2], [100, 2], [100, 2]]
如果需要独立的副本,可以使用列表推导式或
copy()
方法。# 使用列表推导式创建独立副本 lst = [[1, 2] for _ in range(3)] # lst 为 [[1, 2], [1, 2], [1, 2]] lst[0][0] = 100 # lst 变为 [[100, 2], [1, 2], [1, 2]] # 使用 copy() 创建独立副本 import copy lst = [[1, 2]] * 3 lst = [copy.copy(x) for x in lst] # 浅拷贝 lst[0][0] = 100 # lst 变为 [[100, 2], [1, 2], [1, 2]]
(2)非整数乘法
列表乘法只能与整数(
int
)操作,否则会抛出TypeError
。lst = [1, 2, 3] result = lst * 2.5 # TypeError: can't multiply sequence by non-int of type 'float'
(3)空列表的乘法
任何列表乘以
0
都会返回一个空列表。lst = [1, 2, 3] result = lst * 0 # result 为 []
(4)性能问题
列表乘法会创建一个新列表,并将元素复制多次。如果列表很大或重复次数很多,可能会消耗较多内存。
3. 与字符串乘法的区别
字符串的乘法行为与列表类似,但字符串是不可变对象,因此不存在引用问题。
s = "abc" result = s * 3 # result 为 "abcabcabc"
4. 替代方案
如果需要更灵活的元素重复方式,可以使用列表推导式或
itertools.repeat()
。(1)列表推导式
可以自定义每个元素的重复方式。
lst = [1, 2, 3] result = [x for x in lst for _ in range(3)] # result 为 [1, 1, 1, 2, 2, 2, 3, 3, 3]
(2)
itertools.repeat()
用于重复生成某个值,通常与
itertools.chain()
结合使用。import itertools lst = [1, 2, 3] result = list(itertools.chain.from_iterable(itertools.repeat(x, 3) for x in lst)) # result 为 [1, 1, 1, 2, 2, 2, 3, 3, 3] 导入 itertools LST = [1, 2, 3] result = list(itertools.链。from_iterable(itertools.repeat(x, 3) for x in lst)) # 结果为 [1, 1, 1, 2, 2, 2, 3, 3, 3]
5. 总结
列表乘法(
*
)用于重复列表中的元素,生成一个新列表。如果列表包含可变对象,重复操作会创建对这些对象的引用,修改一个会影响所有重复的元素。
列表乘法只能与整数操作,否则会抛出
TypeError
。如果需要独立副本,可以使用列表推导式或
copy()
方法。# 示例 lst = [1, 2, 3] result = lst * 3 # result 为 [1, 2, 3, 1, 2, 3, 1, 2, 3] # 嵌套列表的重复 lst = [[1, 2]] * 3 lst[0][0] = 100 # lst 变为 [[100, 2], [100, 2], [100, 2]]
列表的切片
- 列表的切片返回新的列表,用法和字符串切片相同
a=[1,2,3,4]
b=a[1:3]
print(b) #>>[2,3]
b[0]=100
print(b) #>>[100,3]
print(a) #>>[1,2,3,4]
print(a[::-1]) #>>[4,3,2,1]
print([1,2,3,4,5,6][1:5:2]) #>>[2,4]
在 Python 中,列表切片(slicing)是一个非常方便的操作,但在使用时需要注意一些细节,以避免常见的错误或意外行为。以下是列表切片的注意事项:
1. 切片是左闭右开区间
切片包含起始索引(
start
)对应的元素,但不包含结束索引(stop
)对应的元素。例如,
lst[1:3]
提取的是索引1
和2
的元素,不包含索引3
的元素。lst = [0, 1, 2, 3, 4] print(lst[1:3]) # 输出 [1, 2],不包含索引 3 的元素
2. 索引越界不会报错
如果切片的索引超出列表范围,Python 会自动调整到有效范围,不会抛出错误。
例如,如果
stop
超出列表长度,切片会到列表末尾结束。lst = [0, 1, 2, 3, 4] print(lst[2:10]) # 输出 [2, 3, 4]
3. 负数索引的含义
负数索引表示从列表末尾开始计数。例如,
-1
表示最后一个元素,-2
表示倒数第二个元素。使用负数索引时,需要注意
start
和stop
的顺序,否则可能返回空列表。lst = [0, 1, 2, 3, 4] print(lst[-3:-1]) # 输出 [2, 3] print(lst[-1:-3]) # 输出 [],因为 start > stop
4. 步长的正负影响
步长(
step
)为正数时,切片从左向右提取元素。步长为负数时,切片从右向左提取元素。
如果步长为负数,
start
和stop
的顺序需要反向,否则可能返回空列表。lst = [0, 1, 2, 3, 4] print(lst[1:4:2]) # 输出 [1, 3] print(lst[4:1:-1]) # 输出 [4, 3, 2] print(lst[1:4:-1]) # 输出 [],因为 start < stop 且 step 为负数
5. 切片是浅拷贝
切片操作会返回一个新的列表对象,但其中的元素是原列表的引用(浅拷贝)。
如果列表包含可变对象(如嵌套列表),修改新列表会影响原列表。
lst = [[1, 2], [3, 4]] sub_lst = lst[:] # 浅拷贝 sub_lst[0][0] = 100 # lst 变为 [[100, 2], [3, 4]]
如果需要深拷贝,可以使用
copy.deepcopy()
。import copy lst = [[1, 2], [3, 4]] sub_lst = copy.deepcopy(lst) # 深拷贝 sub_lst[0][0] = 100 # lst 不变
6. 修改列表时切片的注意事项
(1)替换元素
切片可以用于替换列表的部分内容,新内容的长度不需要与原切片长度一致。
lst = [0, 1, 2, 3, 4] lst[1:3] = [10, 20, 30] # lst 变为 [0, 10, 20, 30, 3, 4]
(2)删除元素
将切片赋值为空列表可以删除元素。
lst = [0, 1, 2, 3, 4] lst[1:3] = [] # lst 变为 [0, 3, 4]
(3)插入元素
通过切片可以在指定位置插入元素。
lst = [0, 1, 2, 3, 4] lst[2:2] = [10, 20] # lst 变为 [0, 1, 10, 20, 2, 3, 4]
7. 性能问题
切片操作会创建一个新列表,如果列表很大,可能会消耗较多内存。
如果只需要遍历部分元素,可以使用
itertools.islice()
,它返回一个迭代器,避免创建新列表。import itertools lst = [0, 1, 2, 3, 4] for item in itertools.islice(lst, 1, 4): print(item) # 输出 1, 2, 3
8. 默认值
如果省略
start
,默认从列表开头开始。如果省略
stop
,默认到列表末尾结束。如果省略
step
,默认步长为1
。lst = [0, 1, 2, 3, 4] print(lst[:3]) # 输出 [0, 1, 2] print(lst[2:]) # 输出 [2, 3, 4] print(lst[::2]) # 输出 [0, 2, 4]
9. 总结
切片是左闭右开区间,索引越界不会报错。
负数索引表示从列表末尾开始计数。
步长为负数时,切片从右向左提取元素。
切片是浅拷贝,修改嵌套对象会影响原列表。
切片可以用于替换、删除和插入元素。
切片操作会创建新列表,可能消耗较多内存。
列表的遍历
lst=[1,2,3,4]
for x in lst:
print(x,end = " ")
x=100 #不会修改列表的元素
print(lst) #>>[1,2,3,4]
for i in range(len(lst)):
len[i]=100
print(lst) #>>[100,100,100,100]
在 Python 中,遍历列表是一项常见的操作,但在遍历时需要注意一些细节,以避免常见的错误或性能问题。以下是列表遍历的注意事项:
1. 遍历的基本方法
(1)使用
for
循环
这是最常见的遍历方式,直接遍历列表中的每个元素。
lst = [1, 2, 3, 4] for item in lst: print(item)
(2)使用
enumerate()
获取索引和值
如果需要同时获取元素的索引和值,可以使用
enumerate()
。lst = [1, 2, 3, 4] for index, value in enumerate(lst): print(f"Index: {index}, Value: {value}")
(3)使用
range()
和索引遍历
如果需要通过索引访问元素,可以使用
range()
。lst = [1, 2, 3, 4] for i in range(len(lst)): print(f"Index: {i}, Value: {lst[i]}")
2. 注意事项
(1)不要在遍历时修改列表
在遍历列表时,直接修改列表(如删除或插入元素)可能会导致意外行为或错误。
例如,删除元素会导致列表长度变化,可能跳过某些元素或引发
IndexError
。# 错误示例 lst = [1, 2, 3, 4] for item in lst: if item == 2: lst.remove(item) # 删除元素会导致跳过下一个元素 print(lst) # 输出 [1, 3, 4]
解决方法:遍历列表的副本,或者使用列表推导式生成新列表。
# 正确示例:遍历副本 lst = [1, 2, 3, 4] for item in lst[:]: # 遍历副本 if item == 2: lst.remove(item) # 修改原列表 print(lst) # 输出 [1, 3, 4] # 正确示例:使用列表推导式 lst = [1, 2, 3, 4] lst = [item for item in lst if item != 2] # 生成新列表 print(lst) # 输出 [1, 3, 4]
(2)避免嵌套遍历的性能问题
如果列表很大,嵌套遍历(如双重循环)可能会导致性能问题。
解决方法:优化算法,或使用更高效的数据结构(如集合或字典)。
# 性能较差的嵌套遍历 lst1 = [1, 2, 3] lst2 = [4, 5, 6] for i in lst1: for j in lst2: print(i, j)
(3)遍历空列表
遍历空列表不会抛出错误,但也不会执行循环体。
lst = [] for item in lst: print(item) # 不会执行
(4)遍历时使用
break
和continue
可以使用
break
提前退出循环,或使用continue
跳过当前迭代。lst = [1, 2, 3, 4] for item in lst: if item == 3: break # 退出循环 print(item) # 输出 1, 2
(5)遍历多维列表
如果列表是多维的(如嵌套列表),需要使用嵌套循环遍历。
lst = [[1, 2], [3, 4]] for sub_lst in lst: for item in sub_lst: print(item) # 输出 1, 2, 3, 4
3. 性能优化
(1)使用
while
循环
如果需要更灵活的控制遍历过程,可以使用
while
循环。lst = [1, 2, 3, 4] i = 0 while i < len(lst): print(lst[i]) i += 1
(2)使用
itertools
模块
对于复杂的遍历需求,可以使用
itertools
模块中的工具(如chain
、islice
等)。import itertools lst1 = [1, 2, 3] lst2 = [4, 5, 6] for item in itertools.chain(lst1, lst2): # 合并遍历 print(item)
(3)避免不必要的遍历
如果只需要判断列表中是否存在某个元素,可以使用
in
关键字,而不是遍历整个列表。lst = [1, 2, 3, 4] if 3 in lst: # 直接判断 print("Found")
4. 总结
遍历列表时,避免直接修改列表,可以遍历副本或使用列表推导式。
对于多维列表,使用嵌套循环遍历。
使用
enumerate()
可以同时获取索引和值。使用
break
和continue
控制遍历流程。对于性能敏感的场景,优化算法或使用高效的数据结构。
列表比大小
- 逐个元素比大小,直到分出胜负
- 如果有俩个元素不可比大小,则runtime error
print([1,'a',12]<[1,'b',7]) #>>True
print([1,'a',12]<['ab','b',7]) #>>False
在 Python 中比较列表大小时,需注意以下几点:
逐元素比较:
从第一个元素开始,依次比较对应位置的元素。
若某位置的元素较大,则整个列表更大。
若元素相等,继续比较下一个元素。
list1 = [1, 2, 3] list2 = [1, 2, 4] print(list1 < list2) # 输出: True,因为 3 < 4
长度不同时的比较:
若前面元素相同,较短的列表被认为更小。
list1 = [1, 2] list2 = [1, 2, 3] print(list1 < list2) # 输出: True,list1 更短
不同类型元素的比较:
不同类型元素比较会引发
TypeError
。list1 = [1, 'a'] list2 = [1, 2] # print(list1 < list2) # 会报错: TypeError
嵌套列表的比较:
嵌套列表同样适用逐元素比较规则。
list1 = [1, [2, 3]] list2 = [1, [2, 4]] print(list1 < list2) # 输出: True,因为 3 < 4
空列表的比较:
空列表小于任何非空列表。
list1 = [] list2 = [1] print(list1 < list2) # 输出: True
==
和is
的区别:
==
比较内容是否相同。
is
比较是否为同一对象。list1 = [1, 2, 3] list2 = [1, 2, 3] print(list1 == list2) # 输出: True print(list1 is list2) # 输出: False 列表 1 = [1, 2, 3] 列表 2 = [1, 2, 3] print(list1 == list2) # 输出: True print(list1 is list2) # 输出: False
总结:列表比较是逐元素进行的,类型需一致,长度不同时较短列表更小,嵌套列表同样适用该规则。
第二节 列表基本应用
列表应用例题:校门外的树
某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即01,2,……,L,都种有一棵树。由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树?
输入
第一行有两个整数L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开示一个区域的起始点和终止点的坐标。
输出
包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。
样例输入
500 3
150 300
100 200
470 471
样例输出
298
s = input().split()
L,M = int(s[0]),int(s[1])
good = [True] * (L+1) #good[i] 为True表示坐标i的树还在
for i in range(M):
s = input().split()
start,end = int(s[0]),int(s[1])
for k in range(start,end + 1):
good[k] = False #坐标k处的树被移走了
print(sum(good)) #sum是python函数,可以求列表元素和
#True就是1,False就是0
我们需要计算在移除所有地铁区域内的树后,马路上剩余的树的数量。具体步骤如下:
初始化:创建一个长度为
L + 1
的列表trees
,表示马路上的树。初始时所有树都存在,可以用True
表示树存在,False
表示树被移除。移除树:遍历所有地铁区域,将区域内的树标记为
False
。统计剩余树:遍历
trees
列表,统计True
的数量,即为剩余的树的数量。def remaining_trees(L, regions): # 初始化树的状态,True 表示树存在 trees = [True] * (L + 1) # 遍历所有区域,移除树 for start, end in regions: for i in range(start, end + 1): trees[i] = False # 统计剩余的树 return sum(trees) # 读取输入 L, M = map(int, input().split()) regions = [] for _ in range(M): start, end = map(int, input().split()) regions.append((start, end)) # 计算剩余树的数量 result = remaining_trees(L, regions) print(result)
处理过程
初始化
trees
列表为长度为501
的列表,所有元素为True
。遍历区域:
区域
(150, 300)
:将索引150
到300
的树标记为False
。区域
(100, 200)
:将索引100
到200
的树标记为False
。区域
(470, 471)
:将索引470
到471
的树标记为False
。统计
trees
列表中True
的数量,结果为298
。优化
如果
L
很大(如L = 10000
),上述方法可能效率较低。可以使用集合来存储需要移除的树的位置,然后计算剩余树的数量。def remaining_trees(L, regions): removed = set() for start, end in regions: removed.update(range(start, end + 1)) return L + 1 - len(removed) # 读取输入 L, M = map(int, input().split()) regions = [] for _ in range(M): start, end = map(int, input().split()) regions.append((start, end)) # 计算剩余树的数量 result = remaining_trees(L, regions) print(result) def remaining_trees(L, regions): removed = set() 对于 Start, End in regions: 已删除。update(范围(开始、结束 + 1)) 返回L + 1 - len(已删除) # 读取输入 L, M = map(int, input().split()) 地区 = [] 对于 范围 (M) 中的 _: start, end = map(int, input().split()) 区域。append((开始,结束)) # 计算剩余树的数量 结果 = remaining_trees(L,区域) print(结果)
优化后的处理过程
使用集合
removed
存储所有需要移除的树的位置。遍历区域:
区域
(150, 300)
:将150
到300
的所有整数加入集合。区域
(100, 200)
:将100
到200
的所有整数加入集合。区域
(470, 471)
:将470
和471
加入集合。计算剩余树的数量:
L + 1 - len(removed)
,结果为298
。输出
298
总结
方法 1:直接标记树的状态,适合
L
较小的情况。方法 2:使用集合存储移除的树,适合
L
较大的情况,效率更高。
第三节 列表的朴素排序
列表的排序算法:选择排序
如果有N个元素需要排序,那么首先从N个元素中找到最小的那个放在下标0处 (可以通过让它和原来的下标为0的元素交换位置来实现),然后再从剩下的N-1个元素中找到最小的放在下标1处,然后再从剩下的N-2个元素中找到最小的放在下标2处……直到剩下最后2个元素中最小的被放在了下标n-2处,所有的元素即都就位。
def SelectionSort(a): #选择排序
#将列表a从小到大排序
n = len(a)
for i in range(n-1):
#每次从a[i]及其右边的元素里选出最小的,放在a[i]这个位置
for j in range(i+1,n): #依次考察a[i]右边元素
if a[j] < a[i]:
a[i],a[j] = a[j],a[i]
lst = [1,12,4,56,6,2]
SelectionSort(lst)
print(lst) #>>[1, 2, 4, 6, 12, 56]
选择排序(Selection Sort) 的算法过程。选择排序是一种简单直观的排序算法,其核心思想是每次从未排序的部分中选择最小(或最大)的元素,放到已排序部分的末尾。以下是选择排序的详细步骤和实现:
1. 选择排序的步骤
初始状态:将整个列表视为未排序部分。
找到最小元素:在未排序部分中找到最小的元素。
交换位置:将最小元素与未排序部分的第一个元素交换位置。
缩小未排序范围:将未排序部分的范围缩小一个元素(即已排序部分增加一个元素)。
重复步骤 2-4:直到未排序部分只剩下一个元素。
2. 选择排序的示例
假设有一个列表
[64, 25, 12, 22, 11]
,选择排序的过程如下:
第 1 轮:
未排序部分:
[64, 25, 12, 22, 11]
最小元素:
11
交换
64
和11
,列表变为[11, 25, 12, 22, 64]
第 2 轮:
未排序部分:
[25, 12, 22, 64]
最小元素:
12
交换
25
和12
,列表变为[11, 12, 25, 22, 64]
第 3 轮:
未排序部分:
[25, 22, 64]
最小元素:
22
交换
25
和22
,列表变为[11, 12, 22, 25, 64]
第 4 轮:
未排序部分:
[25, 64]
最小元素:
25
无需交换,列表保持不变
[11, 12, 22, 25, 64]
第 5 轮:
未排序部分:
[64]
最小元素:
64
无需交换,列表保持不变
[11, 12, 22, 25, 64]
最终排序结果为
[11, 12, 22, 25, 64]
。
3. 选择排序的实现
以下是 Python 实现选择排序的代码:
def selection_sort(arr): n = len(arr) for i in range(n - 1): # 遍历到倒数第二个元素 # 找到未排序部分的最小元素的索引 min_index = i for j in range(i + 1, n): if arr[j] < arr[min_index]: min_index = j # 将最小元素与未排序部分的第一个元素交换 arr[i], arr[min_index] = arr[min_index], arr[i] # 测试 arr = [64, 25, 12, 22, 11] selection_sort(arr) print("排序后的列表:", arr) # 输出 [11, 12, 22, 25, 64]
4. 选择排序的时间复杂度
最坏时间复杂度:O(n2),其中 nn 是列表的长度。
最好时间复杂度:O(n2),即使列表已经有序,仍需遍历所有元素。
平均时间复杂度:O(n2)。
选择排序的时间复杂度较高,适合小规模数据排序。
5. 选择排序的空间复杂度
空间复杂度:O(1),选择排序是原地排序算法,不需要额外的存储空间。
6. 选择排序的优缺点
优点:
简单直观,易于实现。
原地排序,不需要额外空间。
缺点:
时间复杂度较高,不适合大规模数据。
不稳定排序(如果交换时破坏了相同元素的相对顺序)。
7. 选择排序的优化
双向选择排序(Bidirectional Selection Sort):
每次同时找到最小和最大元素,分别放到未排序部分的开头和末尾。
可以减少一半的遍历次数。
def bidirectional_selection_sort(arr): n = len(arr) left, right = 0, n - 1 while left < right: min_index, max_index = left, right for i in range(left, right + 1): if arr[i] < arr[min_index]: min_index = i if arr[i] > arr[max_index]: max_index = i # 将最小元素放到左边 arr[left], arr[min_index] = arr[min_index], arr[left] # 如果最大元素在左边,需要调整 if max_index == left: max_index = min_index # 将最大元素放到右边 arr[right], arr[max_index] = arr[max_index], arr[right] left += 1 right -= 1 # 测试 arr = [64, 25, 12, 22, 11] bidirectional_selection_sort(arr) print("排序后的列表:", arr) # 输出 [11, 12, 22, 25, 64]
8. 总结
选择排序是一种简单但低效的排序算法,适合小规模数据。
其核心思想是每次选择未排序部分的最小元素,放到已排序部分的末尾。
时间复杂度为 O(n2),空间复杂度为 O(1)。
可以通过双向选择排序进行优化。
列表的排序算法
时间复杂度O(n2) | 选择排序 | 冒泡排序 | 插入排序 |
时间复杂度O(n*log(n)) | 归并排序 | 快速排序 | python自带排序 |
- 选择排序
- 算法原理:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
- 示例:对于序列 [5, 3, 4, 1, 2],第一次遍历找到最小的元素 1,与第一个元素 5 交换位置,得到 [1, 3, 4, 5, 2];第二次遍历从第二个元素开始找到最小的元素 2,与第二个元素 3 交换位置,以此类推,最终得到有序序列 [1, 2, 3, 4, 5]。
def selection_sort(arr): n = len(arr) # 遍历数组的每一个位置 for i in range(n): # 假设当前位置是最小值的位置 min_idx = i # 在未排序部分中找到最小值的索引 for j in range(i+1, n): if arr[j] < arr[min_idx]: min_idx = j # 将最小值与当前位置交换 arr[i], arr[min_idx] = arr[min_idx], arr[i] return arr
- 冒泡排序
- 算法原理:重复地走访要排序的数列,一次比较两个数据元素,如果顺序不对则进行交换,并一直重复这样的走访操作,直到没有要交换的数据元素为止。
- 示例:对于序列 [5, 3, 4, 1, 2],第一轮比较,5 和 3 比较,交换位置得到 [3, 5, 4, 1, 2],然后 5 和 4 比较交换,得到 [3, 4, 5, 1, 2],5 和 1 比较交换,得到 [3, 4, 1, 5, 2],5 和 2 比较交换,得到 [3, 4, 1, 2, 5];第二轮从第二个元素开始类似比较,最终得到有序序列 [1, 2, 3, 4, 5]。
def bubble_sort(arr): n = len(arr) # 遍历数组的每一个位置 for i in range(n): # 每次遍历将最大的元素“冒泡”到末尾 for j in range(0, n-i-1): # 如果当前元素比下一个元素大,则交换 if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] return arr
- 插入排序
- 算法原理:对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
- 示例:对于序列 [5, 3, 4, 1, 2],假设第一个元素 5 已排序,从第二个元素 3 开始,3 比 5 小,将 3 插入到 5 前面,得到 [3, 5, 4, 1, 2];然后处理 4,4 比 5 小比 3 大,插入到 3 和 5 之间,得到 [3, 4, 5, 1, 2],以此类推,最终得到有序序列 [1, 2, 3, 4, 5]。
def insertion_sort(arr): # 从第二个元素开始遍历 for i in range(1, len(arr)): key = arr[i] # 当前需要插入的元素 j = i - 1 # 将比 key 大的元素向后移动 while j >= 0 and key < arr[j]: arr[j + 1] = arr[j] j -= 1 # 将 key 插入到正确的位置 arr[j + 1] = key return arr
- 归并排序
- 算法原理:采用分治法,将一个数组分成两个子数组,对每个子数组进行排序,然后将排序好的子数组合并成一个最终的排序数组。
- 示例:对于序列 [5, 3, 4, 1, 2],先分成 [5, 3] 和 [4, 1, 2],再继续分成 [5]、[3] 和 [4]、[1, 2],然后 [1, 2] 再分成 [1]、[2]。接着开始合并排序,[3] 和 [5] 合并成 [3, 5],[1] 和 [2] 合并成 [1, 2],[1, 2] 和 [4] 合并成 [1, 2, 4],最后 [3, 5] 和 [1, 2, 4] 合并成 [1, 2, 3, 4, 5]。
def merge_sort(arr): # 如果数组长度大于 1,才需要排序 if len(arr) > 1: mid = len(arr) // 2 # 找到中间位置 left_half = merge_sort(arr[:mid]) # 递归排序左半部分 right_half = merge_sort(arr[mid:]) # 递归排序右半部分 arr = merge(left_half, right_half) # 合并两个有序部分 return arr def merge(left, right): result = [] # 用于存储合并后的结果 i = j = 0 # 比较两个部分的元素,按顺序合并 while i < len(left) and j < len(right): if left[i] < right[j]: result.append(left[i]) i += 1 else: result.append(right[j]) j += 1 # 将剩余的元素添加到结果中 result.extend(left[i:]) result.extend(right[j:]) return result
- 快速排序
- 算法原理:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
- 示例:对于序列 [5, 3, 4, 1, 2],选择一个基准元素,比如 5,将序列中小于 5 的元素放到 5 的左边,大于 5 的元素放到 5 的右边,得到 [3, 4, 1, 2, 5],然后对 [3, 4, 1, 2] 继续进行快速排序,以此类推,最终得到有序序列 [1, 2, 3, 4, 5]。
def quick_sort(arr): # 如果数组长度小于等于 1,直接返回 if len(arr) <= 1: return arr pivot = arr[len(arr) // 2] # 选择中间元素作为基准 # 将数组分为三部分:小于基准、等于基准、大于基准 left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] # 递归排序左半部分和右半部分,然后合并 return quick_sort(left) + middle + quick_sort(right)
- Python 自带排序
- 介绍:Python 中的列表有内置的排序方法
list.sort()
和函数sorted()
,它们的底层实现是 Timsort 算法。- 特点:Timsort 算法结合了归并排序和插入排序的优点,在实际应用中具有很好的性能。它会根据输入数据的特点,自适应地选择合适的排序策略,平均时间复杂度为 O (n*log (n))。
第四节 用排序函数对列表进行简单排序
列表的排序
- a.sort()可以对列表a从小到大排序
- sorted(a)返回a经过从小到大排序后的新列表,a不变
a = [5,7,6,3,4,1,2]
a.sort() #对a从小到大排序
print(a) #>>[1, 2, 3, 4, 5, 6, 7]
a = [5,7,6,3,4,1,2]
b = sorted(a) #a不因此而改变
print(b) #>>[1, 2, 3, 4, 5, 6, 7]
print(a) #>>[5, 7, 6, 3, 4, 1, 2]
a.sort(reverse = True) #对a从大到小排序
print(a) #>>[7, 6, 5, 4, 3, 2, 1]
students = [('John', 'A', 15), # 姓名,成绩,年龄
('Mike', 'C', 19),
('Mike', 'B', 12),
('Mike', 'C', 18),
('Bom', 'D', 10)]
students.sort() #先按姓名,再按成绩,再按年龄排序
print(students)
#>>[('Bom', 'D', 10), ('John', 'A', 15), ('Mike', 'B', 12),('Mike', 'C', 18), ('Mike', 'C', 19)]
定义比较规则的排序
自定义关键字函数 key
def myKey(x): #关键字函数
return x % 10
a = [25,7,16,33,4,1,2]
a.sort(key = myKey)
# key是函数,sort按对每个元素调用该函数的返回值从小到大排序
# [1, 2, 33, 4, 25, 16, 7] 按个位数排序
sorted("This is a test string from Andrew".split(),
key=str.lower))
# ['a', 'Andrew', 'from', 'is', 'string', 'test', 'This'] 不区分大小写排序
在 Python 中,列表的排序可以通过两种方式实现:
list.sort()
方法:原地排序,直接修改原列表。
sorted()
函数:返回一个新的排序列表,原列表不变。以下是详细说明和代码示例:
1.
list.sort()
方法
特点:
原地排序,直接修改原列表。
不返回新的列表。
适用于不需要保留原列表的场景。
语法:
list.sort(key=None, reverse=False)
key
:指定排序规则(例如按某个属性排序)。
reverse
:是否降序排序,默认为False
(升序)。示例:
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5] numbers.sort() # 原地排序,升序 print(numbers) # 输出: [1, 1, 2, 3, 4, 5, 5, 6, 9] numbers.sort(reverse=True) # 原地排序,降序 print(numbers) # 输出: [9, 6, 5, 5, 4, 3, 2, 1, 1]
2.
sorted()
函数
特点:
返回一个新的排序列表,原列表不变。
适用于需要保留原列表的场景。
语法:
sorted(iterable, key=None, reverse=False)
iterable
:可迭代对象(如列表、元组、字符串等)。
key
:指定排序规则。
reverse
:是否降序排序,默认为False
(升序)。示例:
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5] sorted_numbers = sorted(numbers) # 返回新列表,升序 print(sorted_numbers) # 输出: [1, 1, 2, 3, 4, 5, 5, 6, 9] print(numbers) # 原列表不变,输出: [3, 1, 4, 1, 5, 9, 2, 6, 5] sorted_numbers_desc = sorted(numbers, reverse=True) # 返回新列表,降序 print(sorted_numbers_desc) # 输出: [9, 6, 5, 5, 4, 3, 2, 1, 1]
3. 使用
key
参数自定义排序规则
key
参数允许你指定一个函数,用于从每个元素中提取排序依据。例如,按字符串长度排序、按字典的某个键排序等。
示例:
# 按字符串长度排序 words = ["apple", "banana", "cherry", "date"] sorted_words = sorted(words, key=len) # 按长度升序 print(sorted_words) # 输出: ['date', 'apple', 'banana', 'cherry'] # 按字典的某个键排序 students = [ {"name": "Alice", "age": 25}, {"name": "Bob", "age": 22}, {"name": "Charlie", "age": 28}, ] sorted_students = sorted(students, key=lambda x: x["age"]) # 按年龄升序 print(sorted_students) # 输出: [{'name': 'Bob', 'age': 22}, {'name': 'Alice', 'age': 25}, {'name': 'Charlie', 'age': 28}] # 按字符串长度排序 words = [“苹果”, “香蕉”, “樱桃”, “日期”] sorted_words = sorted(words, key=len) # 按长度升序 print(sorted_words) # 输出: ['date', 'apple', 'banana', 'cherry'] # 按字典的某个键排序 学生 = [ {“name”: “爱丽丝”, “age”: 25}, {“In Name”: “Bob”, “Before”: 22}, {“name”: “查理”, “age”: 28}, ] sorted_students = sorted(students, key=lambda x: x[“age”]) # 按年龄升序 打印(sorted_students) #输出: [{'name': 'Bob', 'before': 22}, {'name': 'Alice', 'before': 25}, {'name': 'Charlie', 'before': 28}]
4. 复杂排序:多级排序
如果需要按多个条件排序,可以将
key
参数设置为返回元组的函数。Python 会按元组的顺序依次比较。
示例:
students = [ {"name": "Alice", "age": 25}, {"name": "Bob", "age": 22}, {"name": "Charlie", "age": 25}, ] # 先按年龄升序,再按名字升序 sorted_students = sorted(students, key=lambda x: (x["age"], x["name"])) print(sorted_students) # 输出: # [ # {'name': 'Bob', 'age': 22}, # {'name': 'Alice', 'age': 25}, # {'name': 'Charlie', 'age': 25} # ] 学生 = [ {“name”: “爱丽丝”, “age”: 25}, {“name”: “鲍勃”, “年龄”: 22}, {“name”: “查理”, “age”: 25}, ] # 先按年龄升序,再按名字升序 sorted_students = sorted(students, key=lambda x: (x[“age”], x[“name”])) 打印(sorted_students) # 输出: # [ # {'name': '鲍勃', '年龄': 22}, # {'name': '爱丽丝', 'age': 25}, # {'name': 'Charlie', 'age': 25} # ]
5. 排序的稳定性
Python 的排序算法是稳定的,即相同元素的相对顺序在排序后保持不变。
例如:
data = [(1, "apple"), (2, "banana"), (1, "cherry")] sorted_data = sorted(data, key=lambda x: x[0]) # 按第一个元素排序 print(sorted_data) # 输出: [(1, 'apple'), (1, 'cherry'), (2, 'banana')] 数据 = [(1, “苹果”), (2, “香蕉”), (1, “樱桃”)] sorted_data = sorted(data, key=lambda x: x[0]) # 按第一个元素排序 打印(sorted_data) # 输出: [(1, 'apple'), (1, 'cherry'), (2, 'banana')]
可以看到,
(1, "apple")
和(1, "cherry")
的相对顺序保持不变。
总结
list.sort()
:原地排序,直接修改原列表。
sorted()
:返回新列表,原列表不变。
key
参数:用于自定义排序规则。稳定性:Python 的排序是稳定的,相同元素的相对顺序不变。
第五节 复杂列表的自定义排序
自定义比较规则的排序
- 用不同关键字排序
students = [
('John', 'A', 15), # 姓名,成绩,年龄
('Mike', 'B', 12),
('Mike', 'C', 18),
('Bom', 'D', 10)]
students.sort(key = lambda x: x[2] ) # 按年龄排序
#[('Bom', 'D', 10), ('Mike', 'B', 12), ('John', 'A', 15), ('Mike', 'C', 18)]
students.sort(key = lambda x: x[0] ) # 按姓名排序
# [('Bom', 'D', 10), ('John', 'A', 15), ('Mike', 'B', 12), ('Mike', 'C', 18)]
lambda 表达式
- lambda x: x[2]
- 表示一个函数,参数是x,返回值是 x[2]
k = lambda x,y : x + y #k是一个函数,参数是x,y,返回值是x+y
print(k(4,5)) #>>9
lambda
表达式是 Python 中的一种匿名函数,用于定义简单的、单行的函数。它的语法简洁,适合用于需要函数作为参数的场景(例如排序、过滤等)。
1.
lambda
表达式的语法lambda 参数1, 参数2, ... : 表达式
lambda
是关键字。参数可以有多个,用逗号分隔。
表达式是函数的返回值,不需要写
return
。
2.
lambda
的特点
匿名函数:没有函数名,适合一次性使用。
简洁:适合定义简单的逻辑。
灵活性:可以作为参数传递给其他函数(如
map()
、filter()
、sorted()
等)。
3.
lambda
的使用场景(1) 作为简单函数
# 普通函数 def add(x, y): return x + y # 使用 lambda 实现 add_lambda = lambda x, y: x + y print(add(2, 3)) # 输出: 5 print(add_lambda(2, 3)) # 输出: 5
(2) 作为参数传递给高阶函数
map()
:对可迭代对象的每个元素应用函数。numbers = [1, 2, 3, 4] squared = map(lambda x: x ** 2, numbers) print(list(squared)) # 输出: [1, 4, 9, 16]
filter()
:过滤符合条件的元素。numbers = [1, 2, 3, 4, 5, 6] even_numbers = filter(lambda x: x % 2 == 0, numbers) print(list(even_numbers)) # 输出: [2, 4, 6]
sorted()
:自定义排序规则。students = [ {"name": "Alice", "age": 25}, {"name": "Bob", "age": 22}, {"name": "Charlie", "age": 28}, ] # 按年龄排序 sorted_students = sorted(students, key=lambda x: x["age"]) print(sorted_students) # 输出: [{'name': 'Bob', 'age': 22}, {'name': 'Alice', 'age': 25}, {'name': 'Charlie', 'age': 28}]
(3) 在列表推导式中使用
numbers = [1, 2, 3, 4] squared = [(lambda x: x ** 2)(x) for x in numbers] print(squared) # 输出: [1, 4, 9, 16]
4.
lambda
的局限性
功能简单:只能包含一个表达式,不能包含复杂的逻辑或多行代码。
可读性差:对于复杂的逻辑,使用普通函数更清晰。
5.
lambda
与普通函数的对比普通函数
def add(x, y): return x + y
lambda
表达式add_lambda = lambda x, y: x + y
使用场景
如果逻辑简单且只使用一次,用
lambda
更简洁。如果逻辑复杂或需要复用,用普通函数更合适。
总结
lambda
是一种简洁的匿名函数,适合定义简单的逻辑。常用于需要函数作为参数的场景,如
map()
、filter()
、sorted()
等。对于复杂逻辑,建议使用普通函数以提高代码可读性。
多级排序
def f(x):
return (-x[2],x[1],x[0])
students = [('John', 'A', 15), ('Mike', 'C', 19),
('Wang', 'B', 12), ('Mike', 'B', 12),
('Mike', 'C', 12),
('Mike', 'C', 18),
('Bom', 'D', 10)]
students.sort(key = f ) #先按年龄从高到低,再按成绩从高到低,再按姓名字典序
print(students)
#>>[('Mike', 'C', 18), ('John', 'A', 15), ('Mike', 'B', 12), ('Wang','B', 12), ('Mike', 'C', 12), ('Bom', 'D', 10)]
多级排序是指按照多个条件对数据进行排序。例如,先按第一个条件排序,如果第一个条件相同,再按第二个条件排序,以此类推。在 Python 中,可以通过
sorted()
函数或list.sort()
方法的key
参数实现多级排序。
1. 多级排序的实现方法
key
参数:可以设置为一个返回元组的函数,元组中的每个元素代表一个排序条件。Python 会按照元组的顺序依次比较元素。
2. 多级排序的语法
sorted(iterable, key=lambda x: (条件1, 条件2, ...), reverse=False) sorted(iterable, key=lambda x: (条件1, 条件2, .。。),反向=False)
iterable
:需要排序的可迭代对象(如列表、元组等)。
key
:返回元组的函数,元组中的每个元素代表一个排序条件。
reverse
:是否降序排序,默认为False
(升序)。
3. 示例代码
示例 1:按多个条件排序列表
students = [ {"name": "Alice", "age": 25, "score": 90}, {"name": "Bob", "age": 22, "score": 85}, {"name": "Charlie", "age": 25, "score": 95}, {"name": "David", "age": 22, "score": 80}, ] # 先按年龄升序,再按分数降序 sorted_students = sorted(students, key=lambda x: (x["age"], -x["score"])) print(sorted_students) # 输出: # [ # {'name': 'David', 'age': 22, 'score': 80}, # {'name': 'Bob', 'age': 22, 'score': 85}, # {'name': 'Alice', 'age': 25, 'score': 90}, # {'name': 'Charlie', 'age': 25, 'score': 95} # ]
示例 2:按多个条件排序元组列表
data = [ ("apple", 3), ("banana", 2), ("cherry", 3), ("date", 1), ] # 先按数字升序,再按字母升序 sorted_data = sorted(data, key=lambda x: (x[1], x[0])) print(sorted_data) # 输出: # [ # ('date', 1), # ('banana', 2), # ('apple', 3), # ('cherry', 3) # ]
示例 3:按多个条件排序字符串列表
words = ["apple", "banana", "cherry", "date"] # 先按长度升序,再按字母降序 sorted_words = sorted(words, key=lambda x: (len(x), x), reverse=True) print(sorted_words) # 输出: # ['banana', 'cherry', 'apple', 'date']
4. 多级排序的注意事项
顺序问题:元组中的条件顺序决定了排序的优先级。例如,
(x["age"], x["score"])
表示先按年龄排序,再按分数排序。降序排序:如果需要对某个条件降序排序,可以在该条件前加负号(仅适用于数值类型)。例如,
-x["score"]
表示按分数降序。非数值类型:如果需要对非数值类型(如字符串)降序排序,可以使用
reverse=True
,但这会影响所有条件。
5. 复杂多级排序示例
示例 4:按多个条件排序,部分升序,部分降序
students = [ {"name": "Alice", "age": 25, "score": 90}, {"name": "Bob", "age": 22, "score": 85}, {"name": "Charlie", "age": 25, "score": 95}, {"name": "David", "age": 22, "score": 80}, ] # 先按年龄升序,再按分数降序 sorted_students = sorted( students, key=lambda x: (x["age"], -x["score"]) # 年龄升序,分数降序 ) print(sorted_students) # 输出: # [ # {'name': 'David', 'age': 22, 'score': 80}, # {'name': 'Bob', 'age': 22, 'score': 85}, # {'name': 'Alice', 'age': 25, 'score': 90}, # {'name': 'Charlie', 'age': 25, 'score': 95} # ]
示例 5:按多个条件排序,部分降序,部分升序
data = [ ("apple", 3, 10), ("banana", 2, 20), ("cherry", 3, 15), ("date", 1, 5), ] # 先按第二个元素降序,再按第三个元素升序 sorted_data = sorted( data, key=lambda x: (-x[1], x[2]) # 第二个元素降序,第三个元素升序 ) print(sorted_data) # 输出: # [ # ('apple', 3, 10), # ('cherry', 3, 15), # ('banana', 2, 20), # ('date', 1, 5) # ]
6. 总结
多级排序通过
key
参数返回元组实现,元组中的每个元素代表一个排序条件。可以通过负号(
-
)对数值类型条件降序排序。多级排序非常灵活,适用于各种复杂排序需求。
Python元组的排序
- 元组不能修改,因此无sort函数,可以用sorted得到新的排序后的列表
def f(x):
return (-x[2],x[1],x[0])
students = (('John', 'A', 15), ('Mike', 'C', 19),
('Wang', 'B', 12), ('Mike', 'B', 12),
('Mike', 'C', 12),('Mike', 'C', 18),
('Bom', 'D', 10)) #students是元组
print(sorted(students,key = f)) #sorted的结果是列表
#>>[('Mike', 'C', 19), ('Mike', 'C', 18), ('John', 'A', 15), ('Mike', 'B',
12), ('Wang', 'B', 12), ('Mike', 'C', 12), ('Bom', 'D', 10)]
在 Python 中,元组(
tuple
)是不可变的序列类型,因此不能像列表那样直接使用list.sort()
方法进行原地排序。但是,我们可以使用sorted()
函数对元组进行排序,它会返回一个新的排序后的列表。如果需要元组类型的结果,可以将排序后的列表转换为元组。
1. 使用
sorted()
函数对元组排序
sorted()
函数可以对任何可迭代对象(包括元组)进行排序,并返回一个新的列表。语法:
sorted(iterable, key=None, reverse=False)
iterable
:需要排序的可迭代对象(如元组、列表等)。
key
:指定排序规则(例如按某个属性排序)。
reverse
:是否降序排序,默认为False
(升序)。示例:
# 定义一个元组 numbers = (3, 1, 4, 1, 5, 9, 2, 6, 5) # 对元组进行排序,返回一个新的列表 sorted_numbers = sorted(numbers) print(sorted_numbers) # 输出: [1, 1, 2, 3, 4, 5, 5, 6, 9] # 如果需要元组类型的结果,可以将列表转换为元组 sorted_numbers_tuple = tuple(sorted(numbers)) print(sorted_numbers_tuple) # 输出: (1, 1, 2, 3, 4, 5, 5, 6, 9)
2. 使用
key
参数自定义排序规则
key
参数允许你指定一个函数,用于从每个元素中提取排序依据。示例:
# 按元组中元素的绝对值排序 numbers = (-3, 1, -4, 1, 5, -9, 2, 6, 5) sorted_numbers = sorted(numbers, key=abs) print(sorted_numbers) # 输出: [1, 1, 2, -3, -4, 5, 5, 6, -9]
3. 多级排序
对于包含多个元素的元组,可以按多个条件进行排序。
示例:
# 定义一个包含多个元组的列表 data = [ ("apple", 3), ("banana", 2), ("cherry", 3), ("date", 1), ] # 先按数字升序,再按字母升序 sorted_data = sorted(data, key=lambda x: (x[1], x[0])) print(sorted_data) # 输出: # [ # ('date', 1), # ('banana', 2), # ('apple', 3), # ('cherry', 3) # ]
4. 对元组列表进行排序
如果元组本身是列表的元素,可以直接对列表进行排序。
示例:
# 定义一个元组列表 students = [ ("Alice", 25), ("Bob", 22), ("Charlie", 25), ("David", 22), ] # 按年龄升序排序 sorted_students = sorted(students, key=lambda x: x[1]) print(sorted_students) # 输出: # [ # ('Bob', 22), # ('David', 22), # ('Alice', 25), # ('Charlie', 25) # ]
5. 对元组中的嵌套结构排序
如果元组中包含嵌套结构(如列表、字典等),可以通过
key
参数提取嵌套数据进行排序。示例:
# 定义一个包含嵌套字典的元组列表 students = [ ("Alice", {"age": 25, "score": 90}), ("Bob", {"age": 22, "score": 85}), ("Charlie", {"age": 25, "score": 95}), ("David", {"age": 22, "score": 80}), ] # 按年龄升序,再按分数降序 sorted_students = sorted(students, key=lambda x: (x[1]["age"], -x[1]["score"])) print(sorted_students) # 输出: # [ # ('David', {'age': 22, 'score': 80}), # ('Bob', {'age': 22, 'score': 85}), # ('Alice', {'age': 25, 'score': 90}), # ('Charlie', {'age': 25, 'score': 95}) # ] # 定义一个包含嵌套字典的元组列表 学生 = [ (“爱丽丝”, {“age”: 25, “分数”: 90}), (“鲍勃”, {“age”: 22, “分数”: 85}), (“查理”, {“age”: 25, “分数”: 95}), (“大卫”, {“age”: 22, “分数”: 80}), ] # 按年龄升序,再按分数降序 sorted_students = sorted(students, key=lambda x: (x[1][“age”], -x[1][“score”]))) 打印(sorted_students) # 输出: # [ # ('David', {'age': 22, 'score': 80}), # ('Bob', {'age': 22, 'score': 85}), # ('Alice', {'age': 25, 'score': 90}), # ('Charlie', {'age': 25, 'score': 95}) # ]
6. 总结
元组是不可变的,因此不能直接原地排序。
使用
sorted()
函数对元组排序,返回一个新的列表。可以通过
key
参数自定义排序规则,支持多级排序和嵌套结构排序。如果需要元组类型的结果,可以将排序后的列表转换为元组。
第六节 列表相关函数
列表相关函数
• append (x) 添加元素x到尾部
• count(x) 计算列表中包含多少个x
• extend (x) 添加列表x中的元素到尾部
• insert(i,x) 将元素x插入到下标i处
• remove(x) 删除元素x(如果有多个x就删除第一个),如果x不存在,则引发异常
• reverse(x) 颠倒整个列表
• index(x) 查找元素x,找到则返回第一次出现的下标,找不到则引发异常
• index(x,s) 从下标s开始查找x
a,b = [1,2,3],[5,6]
a.append(b)
print(a) #>>[1, 2, 3, [5, 6]]
b.insert(1,100)
print(a) #>>[1, 2, 3, [5, 100, 6]]
a.extend(b)
print(a) #>>[1, 2, 3, [5, 100, 6], 5, 100, 6]
a.insert(1,'K')
a.insert(3,'K')
print(a) #>>[1, 'K', 2, 'K', 3, [5, 100, 6], 5, 100, 6]
a.remove('K')
print(a) #>>[1, 2, 'K', 3, [5, 100, 6], 5, 100, 6]
a.reverse()
print(a) #>>[6, 100, 5, [5, 100, 6], 3, 'K', 2, 1]
print(a.index('K')) #>>5
try:
print(a.index('m')) #找不到'm', 会引发异常
except Exception as e:
print(e) #>>'m' is not in list
在 Python 中,列表(
list
)是一种非常常用的数据结构,提供了丰富的内置函数和方法来操作列表。以下是列表相关的常用函数和方法:
1. 列表的创建
使用方括号
[]
创建列表。使用
list()
函数将其他可迭代对象(如元组、字符串等)转换为列表。# 创建列表 my_list = [1, 2, 3, 4, 5] # 将元组转换为列表 my_tuple = (1, 2, 3) my_list_from_tuple = list(my_tuple) # 输出: [1, 2, 3] # 将字符串转换为列表 my_string = "hello" my_list_from_string = list(my_string) # 输出: ['h', 'e', 'l', 'l', 'o']
2. 列表的常用方法
(1) 添加元素
append(x)
:在列表末尾添加元素x
。
extend(iterable)
:将可迭代对象的所有元素添加到列表末尾。
insert(i, x)
:在索引i
处插入元素x
。my_list = [1, 2, 3] my_list.append(4) # 添加元素 4 print(my_list) # 输出: [1, 2, 3, 4] my_list.extend([5, 6]) # 添加多个元素 print(my_list) # 输出: [1, 2, 3, 4, 5, 6] my_list.insert(1, 1.5) # 在索引 1 处插入 1.5 print(my_list) # 输出: [1, 1.5, 2, 3, 4, 5, 6]
(2) 删除元素
remove(x)
:删除列表中第一个值为x
的元素,如果不存在则抛出ValueError
。
pop([i])
:删除并返回索引i
处的元素(默认删除最后一个元素)。
clear()
:清空列表。my_list = [1, 2, 3, 4, 5] my_list.remove(3) # 删除元素 3 print(my_list) # 输出: [1, 2, 4, 5] popped_element = my_list.pop(1) # 删除索引 1 处的元素 print(popped_element) # 输出: 2 print(my_list) # 输出: [1, 4, 5] my_list.clear() # 清空列表 print(my_list) # 输出: []
(3) 查找元素
index(x[, start[, end]])
:返回第一个值为x
的元素的索引,如果不存在则抛出ValueError
。
count(x)
:返回值为x
的元素在列表中出现的次数。my_list = [1, 2, 3, 2, 4, 2] index = my_list.index(2) # 查找元素 2 的索引 print(index) # 输出: 1 count = my_list.count(2) # 统计元素 2 的出现次数 print(count) # 输出: 3
(4) 排序和反转
sort(key=None, reverse=False)
:对列表进行原地排序。
reverse()
:原地反转列表。my_list = [3, 1, 4, 1, 5, 9] my_list.sort() # 升序排序 print(my_list) # 输出: [1, 1, 3, 4, 5, 9] my_list.reverse() # 反转列表 print(my_list) # 输出: [9, 5, 4, 3, 1, 1] my_list = [3, 1, 4, 1, 5, 9] my_list。sort() # 升序排序 print(my_list) # 输出: [1, 1, 3, 4, 5, 9] my_list。reverse() # 反转列表 print(my_list) # 输出: [9, 5, 4, 3, 1, 1]
(5) 复制列表
copy()
:返回列表的浅拷贝。my_list = [1, 2, 3] new_list = my_list.copy() print(new_list) # 输出: [1, 2, 3] my_list = [1, 2, 3] new_list = my_list。复制() print(new_list) # 输出: [1, 2, 3]
3. 列表的常用函数
(1)
len()
返回列表的长度。
示例:
my_list = [1, 2, 3, 4, 5] length = len(my_list) print(length) # 输出: 5
(2)排序
sorted()
返回一个新的排序后的列表,原列表不变。
示例:
my_list = [3, 1, 4, 1, 5] sorted_list = sorted(my_list) print(sorted_list) # 输出: [1, 1, 3, 4, 5]
(3)
min()
和max()
返回列表中的最小值和最大值。
示例:
my_list = [3, 1, 4, 1, 5] min_value = min(my_list) # 输出: 1 max_value = max(my_list) # 输出: 5
(4)
sum()
返回列表中所有元素的和。
示例:
my_list = [1, 2, 3, 4, 5] total = sum(my_list) print(total) # 输出: 15
(5)
any()
和all()
any()
:如果列表中至少有一个元素为True
,则返回True
。
all()
:如果列表中所有元素都为True
,则返回True
。示例:
my_list = [True, False, True] print(any(my_list)) # 输出: True print(all(my_list)) # 输出: False
列表映射
- map(function, sequence),可用于将一个序列(列表、元组、集合...)映射到另一个序列返回一个延时求值对象,可以转换成list,tuple,set....
def f(x):
print(x,end="")
return x*x
a = map(f,[1,2,3])
print(list(a)) #>>123[1, 4, 9]
print(tuple(a)) #>>()
a = list(map(lambda x:2*x, [2,3,4]))
print(a) #>>[4,6,8]
map 用于输入
x,y,z = map(int,input().split())
print(x,y,z)
输入:1 23 45
输出:1 23 45
map 映射多个序列
list1 = [1,2,3,100]
list2 = {10,20,30}
tuple1 = [100,200,300,'ok','me']
x = list(map(lambda x,y,z : x+y+z, list1, list2, tuple1))
print(x)
#>>[111, 222, 333]
map()
是 Python 中的一个内置函数,用于对可迭代对象(如列表、元组等)中的每个元素应用一个函数,并返回一个迭代器。map()
函数的核心思想是“映射”,即将一个函数映射到可迭代对象的每个元素上。
1.
map()
函数的语法map(function, iterable, ...)
function
:要应用的函数。
iterable
:可迭代对象(如列表、元组等)。返回值:返回一个迭代器,可以通过
list()
、tuple()
等函数转换为具体的序列。
2.
map()
函数的基本用法示例 1:对列表中的每个元素应用函数
# 定义一个函数:将数字加 10 def add_ten(x): return x + 10 numbers = [1, 2, 3, 4, 5] result = map(add_ten, numbers) # 对每个元素应用 add_ten 函数 print(list(result)) # 输出: [11, 12, 13, 14, 15] # 定义一个函数:将数字加 10 def add_ten(x): 返回 X + 10 数字 = [1, 2, 3, 4, 5] result = map(add_ten, numbers) # 对每个元素应用 add_ten 函数 print(list(result)) # 输出: [11, 12, 13, 14, 15]
示例 2:使用
lambda
表达式numbers = [1, 2, 3, 4, 5] result = map(lambda x: x ** 2, numbers) # 对每个元素平方 print(list(result)) # 输出: [1, 4, 9, 16, 25]
3.
map()
函数的多参数支持
map()
函数可以接受多个可迭代对象,并将函数依次应用到这些可迭代对象的对应元素上。示例:
# 定义函数:计算两个数的和 def add(x, y): return x + y numbers1 = [1, 2, 3] numbers2 = [4, 5, 6] result = map(add, numbers1, numbers2) # 对每对元素应用 add 函数 print(list(result)) # 输出: [5, 7, 9]
4.
map()
函数的返回值
map()
函数返回的是一个迭代器,而不是列表。如果需要列表或其他序列类型,可以使用list()
、tuple()
等函数进行转换。示例:
numbers = [1, 2, 3, 4, 5] result = map(lambda x: x * 2, numbers) # 返回迭代器 print(result) # 输出: <map object at 0x7f9b1c2d5f10> # 转换为列表 result_list = list(result) print(result_list) # 输出: [2, 4, 6, 8, 10]
5.
map()
函数的优势
惰性求值:
map()
返回的是迭代器,只有在需要时才会计算,适合处理大规模数据。代码简洁:结合
lambda
表达式,可以写出非常简洁的代码。多参数支持:可以同时处理多个可迭代对象。
6.
map()
函数的注意事项
函数参数数量:如果函数需要多个参数,
map()
必须提供相应数量的可迭代对象。迭代器消耗:
map()
返回的迭代器只能遍历一次,遍历完后会被消耗。性能问题:对于简单的操作,列表推导式通常比
map()
更快且更易读。
7.
map()
函数的替代方案
列表推导式:适合简单的映射操作,代码更直观。
numbers = [1, 2, 3, 4, 5] result = [x ** 2 for x in numbers] # 使用列表推导式 print(result) # 输出: [1, 4, 9, 16, 25]
for
循环:适合需要复杂逻辑的场景。numbers = [1, 2, 3, 4, 5] result = [] for x in numbers: result.append(x ** 2) print(result) # 输出: [1, 4, 9, 16, 25]
8.
map()
函数的实际应用示例 1:将字符串列表转换为整数列表
str_numbers = ["1", "2", "3", "4", "5"] int_numbers = list(map(int, str_numbers)) # 将字符串转换为整数 print(int_numbers) # 输出: [1, 2, 3, 4, 5]
示例 2:计算多个列表中对应元素的和
list1 = [1, 2, 3] list2 = [4, 5, 6] list3 = [7, 8, 9] result = list(map(lambda x, y, z: x + y + z, list1, list2, list3)) print(result) # 输出: [12, 15, 18]
示例 3:将列表中的字符串首字母大写
words = ["apple", "banana", "cherry"] capitalized_words = list(map(str.capitalize, words)) print(capitalized_words) # 输出: ['Apple', 'Banana', 'Cherry']
示例4: 基本输入匹配用户输入一组数字,使用
map()
函数将其转换为整数列表。# 用户输入:1 2 3 4 5 user_input = input("请输入一组数字,用空格分隔: ") numbers = list(map(int, user_input.split())) # 将输入转换为整数列表 print(numbers) # 输出: [1, 2, 3, 4, 5]
9. 总结
map()
函数用于对可迭代对象中的每个元素应用一个函数。返回一个迭代器,可以通过
list()
、tuple()
等函数转换为具体序列。适合处理大规模数据和需要复用函数的场景。
对于简单操作,列表推导式通常更直观和高效。
列表过滤
- filter(function, sequence),抽取序列中令function(x)为True的元素x
- 返回一个延时求值对象,可以转换成list,tuple,set...
def f(x):
return x % 2 == 0
lst = tuple(filter(f,[1,2,3,4,5]))
#抽取出偶数
print(lst)
#>>(2, 4)
列表过滤是指从列表中筛选出满足特定条件的元素。在 Python 中,列表过滤可以通过多种方式实现,最常见的方法是使用 列表推导式 和
filter()
函数。
1. 列表推导式
列表推导式是一种简洁且高效的方式,用于从列表中筛选出满足条件的元素。
语法:
[表达式 for 元素 in 列表 if 条件]
示例:
# 过滤出列表中的偶数 numbers = [1, 2, 3, 4, 5, 6] even_numbers = [x for x in numbers if x % 2 == 0] print(even_numbers) # 输出: [2, 4, 6] # 过滤出长度大于 5 的字符串 words = ["apple", "banana", "cherry", "date"] long_words = [word for word in words if len(word) > 5] print(long_words) # 输出: ['banana', 'cherry'] # 过滤出列表中的偶数 数字 = [1, 2, 3, 4, 5, 6] even_numbers = [x for x in numbers if x % 2 == 0] print(even_numbers) # 输出: [2, 4, 6] # 过滤出长度大于 5 的字符串 words = [“苹果”, “香蕉”, “樱桃”, “日期”] long_words = [如果 len(word) > 5] print(long_words) # 输出: ['banana', 'cherry']
2.
filter()
函数
filter()
函数接受一个函数和一个可迭代对象(如列表),并返回一个迭代器,其中包含满足条件的元素。语法:
filter(函数, 列表)
示例:
# 过滤出列表中的偶数 numbers = [1, 2, 3, 4, 5, 6] even_numbers = filter(lambda x: x % 2 == 0, numbers) print(list(even_numbers)) # 输出: [2, 4, 6] # 过滤出长度大于 5 的字符串 words = ["apple", "banana", "cherry", "date"] long_words = filter(lambda word: len(word) > 5, words) print(list(long_words)) # 输出: ['banana', 'cherry'] # 过滤出列表中的偶数 数字 = [1, 2, 3, 4, 5, 6] even_numbers = 过滤器(lambda x: x % 2 == 0, 数字) print(list(even_numbers)) # 输出: [2, 4, 6] # 过滤出长度大于 5 的字符串 words = [“苹果”, “香蕉”, “樱桃”, “日期”] long_words = filter(lambda word: len(word) > 5, words) print(list(long_words)) # 输出: ['banana', 'cherry']
3. 列表推导式 vs
filter()
函数
列表推导式:
更直观,代码更易读。
适合简单的过滤操作。
直接返回列表。
filter()
函数:
适合需要复用函数的场景。
返回一个迭代器,节省内存(适合处理大数据集)。
需要显式转换为列表(如
list(filter(...))
)。示例对比:
# 列表推导式 even_numbers = [x for x in numbers if x % 2 == 0] # filter() 函数 even_numbers = filter(lambda x: x % 2 == 0, numbers) # 列表推导式 even_numbers = [x for x in numbers if x % 2 == 0] # filter() 函数 even_numbers = filter(lambda x: x % 2 == 0, 数字)
4. 带条件的列表过滤
可以在列表推导式中添加多个条件,筛选出满足所有条件的元素。
示例:
# 过滤出列表中大于 2 且小于 5 的元素 numbers = [1, 2, 3, 4, 5, 6] filtered_numbers = [x for x in numbers if x > 2 and x < 5] print(filtered_numbers) # 输出: [3, 4]
5. 嵌套列表过滤
可以对嵌套列表(多维列表)进行过滤操作。
示例:
# 过滤出二维列表中所有大于 5 的元素 matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] filtered_matrix = [[x for x in row if x > 5] for row in matrix] print(filtered_matrix) # 输出: # [ # [], # [6], # [7, 8, 9] # ]
6. 使用自定义函数进行过滤
可以定义一个函数,并将其用于列表过滤。
示例:
# 自定义函数:判断是否为偶数 def is_even(x): return x % 2 == 0 numbers = [1, 2, 3, 4, 5, 6] even_numbers = [x for x in numbers if is_even(x)] print(even_numbers) # 输出: [2, 4, 6] # 使用 filter() 函数 even_numbers = filter(is_even, numbers) print(list(even_numbers)) # 输出: [2, 4, 6]
7. 性能考虑
列表推导式:适合小规模数据,代码简洁易读。
filter()
函数:适合大规模数据,返回迭代器,节省内存。
8. 实际应用示例
示例 1:过滤出列表中的正数
numbers = [-1, 2, -3, 4, -5, 6] positive_numbers = [x for x in numbers if x > 0] print(positive_numbers) # 输出: [2, 4, 6] 数字 = [-1, 2, -3, 4, -5, 6] positive_numbers = [x for x in numbers if x > 0] print(positive_numbers) # 输出: [2, 4, 6]
示例 2:过滤出列表中包含特定字符的字符串
words = ["apple", "banana", "cherry", "date"] filtered_words = [word for word in words if "a" in word] print(filtered_words) # 输出: ['apple', 'banana', 'date']
示例 3:过滤出字典列表中满足条件的字典
students = [ {"name": "Alice", "age": 25}, {"name": "Bob", "age": 22}, {"name": "Charlie", "age": 28}, ] filtered_students = [student for student in students if student["age"] > 23] print(filtered_students) # 输出: # [ # {'name': 'Alice', 'age': 25}, # {'name': 'Charlie', 'age': 28} # ]
9. 总结
列表过滤可以通过 列表推导式 或
filter()
函数 实现。列表推导式更直观,适合简单操作。
filter()
函数适合复用函数或处理大数据集。可以根据需求选择合适的方式。
第七节 列表生成式
列表生成式
[x * x for x in range(1, 11)]
#>> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
[x * x for x in range(1, 11) if x % 2 == 0]
#>> [4, 16, 36, 64, 100]
#倆重循环
[m + n for m in 'ABC' for n in 'XYZ']
#>> ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
#倆重循环生成列表嵌套
[[m + n for m in 'ABC'] for n in 'XYZ']
#>> [['AX', 'BX', 'CX'], ['AY', 'BY', 'CY'], ['AZ', 'BZ', 'CZ']]
L = ['Hello', 'World', 18, 'Apple', None]
[s.lower() for s in L if isinstance(s,str)]
#>> ['hello', 'world', 'apple'] 收集字符串
[s for s in L if isinstance(s,int )] #>>[18] 收集整数
元组生成式
print(tuple(x * x for x in range(1, 11)))
#>>(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
列表生成式
基本语法:
[expression for item in iterable if condition]
expression
是对每个元素应用的表达式。item
是当前遍历到的元素。iterable
是一个可迭代对象(如列表、元组、集合等)。condition
(可选)是一个过滤条件。元组生成式
基本语法:
(expression for item in iterable if condition)
第八节 二维列表
二维列表
- 二维列表a可以看作是矩阵,a[i][j]就是第i行第j列的元素
- 错误的生成二维列表的方法:
a = [0, 0, 0]
b = [a] * 3
#b有三个元素,都是指针,都和a指向同一地方 不是矩阵
print(b) #>>[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
b[0][1] = 1
a[2] = 100
print(b) #>>[[0, 1, 100], [0, 1, 100], [0, 1, 100]]
定义二维列表
- 正确做法:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] #矩阵
print(matrix) #>>[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(matrix[1][2],matrix[2][2]) #>>6 9
matrix[1][1] = 100
print(matrix) #>>[[1, 2, 3], [4, 100, 6], [7, 8, 9]]
#列表生成式
matrix = [[0 for i in range(3)] for i in range(3)]
print(matrix) #>>[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
matrix = [[i*3+j for j in range(3)] for i in range(2)]
print(matrix) #>>[[0, 1, 2], [3, 4, 5]]
#生成一个3行4列的矩阵,所有元素都是0
lst = []
for i in range(3):
lst.append([0] * 4)
lst[0][0] = lst[2][3] = 100
定义二维元组
matrix = ((1, 2, 3), (4, 5, 6), (7, 8, 9))
print(matrix)
#>>((1, 2, 3), (4, 5, 6), (7, 8, 9))
matrix = tuple(tuple(0 for i in range(3)) for i in range(3))
print(matrix) #>>((0, 0, 0), (0, 0, 0), (0, 0, 0))
1. 二维列表的定义
二维列表可以看作是列表的列表,即每个元素本身又是一个列表,常用于表示矩阵、表格等二维结构的数据。
# 手动初始化一个二维列表 matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] # 使用嵌套循环初始化一个 3x4 的二维列表,初始值都为 0 rows = 3 cols = 4 matrix_zeros = [[0 for _ in range(cols)] for _ in range(rows)] print("手动初始化的二维列表:") for row in matrix: print(row) print("\n使用嵌套循环初始化的二维列表:") for row in matrix_zeros: print(row)
2. 二维列表的访问
可以通过两个索引来访问二维列表中的元素,第一个索引表示行,第二个索引表示列。
matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] # 访问第 2 行(索引为 1)第 3 列(索引为 2)的元素 element = matrix[1][2] print("访问的元素是:", element)
3. 二维列表的遍历
可以使用嵌套循环来遍历二维列表中的每个元素。
matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] # 遍历二维列表并打印每个元素 for row in matrix: for element in row: print(element, end=" ") print()
4. 二维列表的排序
如果要对二维列表进行排序,可以根据特定的规则来排序,例如按照某一列的值进行排序。
students = [ ["Alice", 85], ["Bob", 92], ["Charlie", 78] ] # 按照成绩(每个子列表的第二个元素)进行排序 sorted_students = sorted(students, key=lambda x: x[1]) print("按成绩排序后的学生列表:") for student in sorted_students: print(student)
5. 二维列表的常见操作
5.1 添加元素
可以向二维列表中添加新的行或修改已有行的元素。
matrix = [ [1, 2, 3], [4, 5, 6] ] # 添加一行 new_row = [7, 8, 9] matrix.append(new_row) # 修改第 1 行(索引为 0)第 2 列(索引为 1)的元素 matrix[0][1] = 10 print("修改后的二维列表:") for row in matrix: print(row)
5.2 计算二维列表的长度
可以分别计算二维列表的行数和列数。
matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] rows = len(matrix) cols = len(matrix[0]) print(f"二维列表的行数: {rows}, 列数: {cols}")
第九节 列表拷贝
列表拷贝
a = [1,2,3,4]
b = a[:] #b是a的拷贝,b和a不是同一个对象,指向不同东西
b[0] = 5
print(a) #>>[1, 2, 3, 4]
b += [10]
print(a) #>>[1, 2, 3, 4]
print(b) #>>[5, 2, 3, 4, 10]
列表深拷贝
a=[1,[2]]
b=a[:]
b.append(4)
print(b) #>>[1, [2], 4]
a[1].append(3)
print(a) #>>[1, [2, 3]]
print(b) #>>[1, [2, 3], 4]
- 未能进行深拷贝!
浅拷贝和深拷贝是在处理对象复制时的两种不同方式,它们的主要区别体现在以下几个方面:
复制层次
- 浅拷贝:只复制对象的一层结构。对于对象中的基本数据类型(如整数、浮点数、布尔值等),会直接复制其值;而对于引用数据类型(如列表、字典、自定义对象等),仅仅复制对象的引用,也就是新对象和原对象中的引用指向同一个内存地址。
- 深拷贝:会递归地复制对象及其所有嵌套的对象。它会创建一个完全独立的新对象,新对象和原对象中的所有元素(包括嵌套的元素)都拥有各自独立的内存空间,彼此之间没有任何关联。
内存占用
- 浅拷贝:由于只复制了对象的引用,并没有为引用指向的对象分配新的内存空间,所以浅拷贝所占用的额外内存相对较少,主要是新对象本身的内存开销。
- 深拷贝:需要递归地复制对象及其所有嵌套的对象,会为每个对象都分配新的内存空间,因此深拷贝所占用的额外内存通常比浅拷贝多,尤其是当对象嵌套层次较深或者包含大量元素时,内存开销会显著增加。
数据独立性
- 浅拷贝:新对象和原对象共享部分数据(即引用数据类型的部分)。当修改原对象中引用数据类型的元素时,浅拷贝的对象也会受到影响;反之,修改浅拷贝对象中引用数据类型的元素,原对象同样会受到影响。
- 深拷贝:新对象和原对象是完全独立的,它们各自拥有自己的数据副本。对原对象进行任何修改都不会影响到深拷贝的对象,反之亦然。
实现复杂度
- 浅拷贝:实现相对简单。在许多编程语言中,都提供了内置的浅拷贝方法或函数,例如 Python 中的
copy.copy()
函数,Java 中通过实现Cloneable
接口并重写clone()
方法即可实现浅拷贝。- 深拷贝:实现相对复杂。由于需要递归地复制对象及其所有嵌套的对象,因此在实现深拷贝时需要考虑对象的嵌套结构和引用关系。有些编程语言提供了内置的深拷贝函数,如 Python 中的
copy.deepcopy()
函数,但在其他情况下,可能需要手动编写递归复制的代码。应用场景
- 浅拷贝:适用于只需要复制对象的外层结构,而不需要对内部元素进行独立修改的场景。例如,当需要对一个对象进行备份,但又希望备份和原对象共享部分数据时,可以使用浅拷贝。
- 深拷贝:适用于需要创建一个完全独立的对象副本,且不希望原对象和副本之间存在任何数据关联的场景。例如,在多线程环境中,为了避免多个线程同时修改同一个对象而产生数据竞争问题,可以使用深拷贝来创建对象的副本供每个线程独立使用。
元组和列表互转
a=[1,2,3]
b=tuple(a) #b: (1,2,3)
c=list(b)
#c: [1,2,3]
t = (1, 3, 2)
(a, b, c) = t
# a = 1, b = 3, c = 2
s = [1,2,3]
[a,b,c] = s
# a = 1, b = 2, c = 3
元组、列表和字符串互转
print(list("hello"))
#>>['h', 'e', 'l', 'l', 'o']
print("".join(['a','44','c'])) #>>a44c
print(tuple("hello"))
#>>('h', 'e', 'l', 'l', 'o')
print("".join(('a','44','c'))) #>>a44c
join()
方法:用于将序列(如列表、元组)中的元素以指定的分隔符连接成一个新的字符串。基本用法
join()
方法需要一个可迭代对象作为参数,该可迭代对象应包含字符串元素。join()
会遍历这个可迭代对象,并将其中的所有字符串通过调用者字符串作为分隔符连接起来。语法:
separator.join(iterable)
separator
是用来连接字符串的分隔符。
iterable
是一个可迭代对象,通常是一个字符串列表或元组。示例
1. 使用空格作为分隔符连接单词列表:
words = ['Hello', 'world', 'from', 'Python'] sentence = ' '.join(words) print(sentence) # 输出: Hello world from Python
2. 使用逗号和空格作为分隔符连接项目列表:
items = ['apple', 'banana', 'cherry'] formatted_items = ', '.join(items) print(formatted_items) # 输出: apple, banana, cherry
3. 连接字符列表形成一个字符串:
characters = ['P', 'y', 't', 'h', 'o', 'n'] word = ''.join(characters) print(word) # 输出: Python
注意事项
非字符串元素:如果尝试连接的可迭代对象中包含了非字符串元素,将会抛出
TypeError
。为避免这种情况,可以先将所有元素转换为字符串:mixed_list = [1, 'apple', 2, 'banana'] result = ', '.join(str(item) for item in mixed_list) print(result) # 输出: 1, apple, 2, banana
效率考虑:对于大量的字符串连接操作,使用
join()
比使用+
运算符更高效。因为每次使用+
都会创建一个新的字符串对象,而join()
只需要一次内存分配。空字符串作为分隔符:当不需要任何分隔符时,可以直接使用空字符串
''
作为join()
的第一个参数。实际应用示例
假设你需要将一个句子中的单词顺序反转并重新连接成一个新的句子:
sentence = "The quick brown fox jumps over the lazy dog" words = sentence.split() # 将句子分割成单词列表 reversed_sentence = ' '.join(reversed(words)) # 反转单词列表并重新连接 print(reversed_sentence) # 输出: dog lazy the over jumps fox brown quick The
测试题答案及解析
041:成绩排序
描述
给出班里某门课程的成绩单,请你按成绩从高到低对成绩单排序输出,如果有相同分数则名字字典序小的在前。
输入
第一行为n (0 < n < 20),表示班里的学生数目;
接下来的n行,每行为每个学生的名字和他的成绩, 中间用单个空格隔开。名字只包含字母且长度不超过20,成绩为一个不大于100的非负整数。
输出
把成绩单按分数从高到低的顺序进行排序并输出,每行包含名字和分数两项,之间有一个空格。
样例输入
4 Kitty 80 Hanmeimei 90 Joey 92 Tim 28
样例输出
Joey 92 Hanmeimei 90 Kitty 80 Tim 28
要对成绩单进行排序,我们可以按照以下步骤来实现:
- 读取输入的学生数目。
- 读取每个学生的名字和成绩,并存储在一个列表中。
- 根据成绩和名字对列表进行排序。
- 输出排序后的结果。
# 读取学生数量 n = int(input()) # 存储学生信息的列表 students = [] # 循环读取每个学生的信息 for _ in range(n): name, score = input().split() score = int(score) students.append((name, score)) # 自定义排序规则 # 先按成绩从高到低排序,如果成绩相同则按名字字典序从小到大排序 students.sort(key=lambda x: (-x[1], x[0])) # 输出排序后的结果 for name, score in students: print(name, score)
代码解释:
- 读取学生数量:使用
input()
函数读取输入的第一行,并将其转换为整数n
,表示学生的数量。- 存储学生信息:创建一个空列表
students
,用于存储每个学生的名字和成绩。通过循环n
次,每次读取一行输入,使用split()
方法将名字和成绩分开,并将成绩转换为整数,然后将名字和成绩作为一个元组添加到students
列表中。- 自定义排序规则:使用
sort()
方法对students
列表进行排序。key=lambda x: (-x[1], x[0])
是一个自定义的排序规则,其中-x[1]
表示按成绩从高到低排序(因为使用了负号),x[0]
表示如果成绩相同,则按名字的字典序从小到大排序。- 输出排序结果:遍历排序后的
students
列表,将每个学生的名字和成绩输出,中间用一个空格分隔。复杂度分析:
- 时间复杂度:排序操作的时间复杂度为O(nlogn) ,其中 n是学生的数量。
- 空间复杂度:主要的空间开销是存储学生信息的列表,空间复杂度为 O(n)。
易错点:打印列表
在Python中,打印列表是一个非常常见的操作。根据你的需求,打印列表的方式可以有所不同。下面我会展示几种常见的方式来打印列表,并解释它们的适用场景。
1. 直接打印整个列表
最简单的方法是直接使用
print()
函数来打印整个列表。这种方式会显示列表的所有元素以及它们的格式(包括方括号和逗号)。my_list = ['apple', 'banana', 'cherry'] print(my_list) # 输出: ['apple', 'banana', 'cherry']
2. 打印列表中的每个元素
如果你希望以更友好的方式显示列表中的每个元素,可以使用循环逐个打印每个元素。
使用
for
循环:my_list = ['apple', 'banana', 'cherry'] for item in my_list: print(item) # 输出: # apple # banana # cherry
使用
join()
方法(适用于字符串列表):如果你有一个字符串列表并且希望将它们用特定的分隔符连接起来再打印,可以使用
join()
方法。my_list = ['apple', 'banana', 'cherry'] print(', '.join(my_list)) # 输出: apple, banana, cherry
注意:这种方法只适用于所有元素都是字符串的情况。如果列表包含非字符串元素,你需要先将它们转换为字符串:
my_list = ['apple', 42, 'cherry'] print(', '.join(str(item) for item in my_list)) # 输出: apple, 42, cherry
3. 格式化输出
有时你可能希望以某种特定的格式输出列表内容。Python提供了多种格式化字符串的方法,以下是几种常见的例子。
使用
f-string
(Python 3.6+):my_list = ['apple', 'banana', 'cherry'] for index, item in enumerate(my_list): print(f"{index + 1}: {item}") # 输出: # 1: apple # 2: banana # 3: cherry
使用
format()
方法:my_list = ['apple', 'banana', 'cherry'] for index, item in enumerate(my_list): print("{}: {}".format(index + 1, item)) # 输出: # 1: apple # 2: banana # 3: cherry
4. 打印嵌套列表
如果你有一个嵌套列表(即列表中的元素也是列表),你可以使用递归或嵌套循环来打印其内容。
使用嵌套循环:
nested_list = [['apple', 'banana'], ['carrot', 'lettuce'], ['mango', 'peach']] for sublist in nested_list: for item in sublist: print(item) # 输出: # apple # banana # carrot # lettuce # mango # peach
使用递归函数(适用于任意深度的嵌套列表):
def print_nested_list(nested_list): for item in nested_list: if isinstance(item, list): print_nested_list(item) else: print(item) nested_list = [['apple', 'banana'], ['carrot', ['lettuce', 'spinach']], ['mango', 'peach']] print_nested_list(nested_list) # 输出: # apple # banana # carrot # lettuce # spinach # mango # peach
总结
直接打印:适合快速查看列表内容。
逐个打印:适合需要更清晰、用户友好的输出。
格式化输出:适合需要对输出进行定制化处理的情况。
嵌套列表:处理复杂数据结构时,可以使用嵌套循环或递归。
042:图像模糊处理
描述
给定n行m列的图像各像素点的灰度值,要求用如下方法对其进行模糊化处理:
1. 四周最外侧的像素点灰度值不变;
2. 中间各像素点新灰度值为该像素点及其上下左右相邻四个像素点原灰度值的平均(舍入到最接近的整数)。
输入
第一行包含两个整数n和m,表示图像包含像素点的行数和列数。1 <= n <= 100,1 <= m <= 100。
接下来n行,每行m个整数,表示图像的每个像素点灰度。相邻两个整数之间用单个空格隔开,每个元素均在0~255之间。
输出
n行,每行m个整数,为模糊处理后的图像。相邻两个整数之间用单个空格隔开。
样例输入
4 5
100 0 100 0 50
50 100 200 0 0
50 50 100 100 200
100 100 50 50 100
样例输出
100 0 100 0 50
50 80 100 60 0
50 80 100 90 200
100 100 50 50 100
要实现图像的模糊处理,我们需要按照题目描述的要求对图像的每个像素点进行处理。具体步骤如下:
读取输入:获取图像的行数
n
和列数m
,以及每个像素点的灰度值。处理边界像素:四周最外侧的像素点灰度值不变。
处理中间像素:中间各像素点的新灰度值为该像素点及其上下左右相邻四个像素点原灰度值的平均(舍入到最接近的整数)。
输出结果:输出模糊处理后的图像。
以下是完整的 Python 实现代码:
def blur_image(n, m, image): # 创建一个新的图像矩阵,用于存储模糊后的结果 blurred_image = [[0 for _ in range(m)] for _ in range(n)] # 遍历每个像素点 for i in range(n): for j in range(m): # 如果是最外侧的像素点,灰度值不变 if i == 0 or i == n - 1 or j == 0 or j == m - 1: blurred_image[i][j] = image[i][j] else: # 计算中间像素点及其上下左右四个相邻像素点的平均值 total = ( image[i][j] + # 当前像素点 image[i - 1][j] + # 上 image[i + 1][j] + # 下 image[i][j - 1] + # 左 image[i][j + 1] # 右 ) average = round(total / 5) # 计算平均值并舍入到最接近的整数 blurred_image[i][j] = average return blurred_image # 读取输入 n, m = map(int, input().split()) image = [list(map(int, input().split())) for _ in range(n)] # 进行模糊处理 blurred_image = blur_image(n, m, image) # 输出结果 for row in blurred_image: print(" ".join(map(str, row)))
代码说明
输入读取:
使用
input().split()
读取第一行的n
和m
。使用列表推导式读取接下来的
n
行,每行包含m
个灰度值。模糊处理:
创建一个新的二维列表
blurred_image
,用于存储模糊后的结果。遍历每个像素点:
如果是最外侧的像素点(即第一行、最后一行、第一列或最后一列),灰度值不变。
如果是中间像素点,计算其与上下左右四个相邻像素点的平均值,并舍入到最接近的整数。
输出结果:
遍历模糊处理后的图像矩阵,逐行输出灰度值,每个值之间用空格分隔。
复杂度分析
时间复杂度:O(n * m),需要遍历每个像素点。
空间复杂度:O(n * m),需要存储模糊处理后的图像。
总结
通过遍历图像的每个像素点,并根据其位置决定是否进行模糊处理。
使用简单的数学计算和条件判断即可实现题目要求。
代码清晰易懂,适合处理小规模图像(如题目中的 100x100 像素)。
043:向量点积计算
描述
在线性代数、计算几何中,向量点积是一种十分重要的运算。
给定两个n维向量a=(a1,a2,...,an)和b=(b1,b2,...,bn),求点积a·b=a1b1+a2b2+...+anbn。
输入
第一行是一个整数n。1 <= n <= 1000。
第二行包含n个整数a1,a2,...,an。
第三行包含n个整数b1,b2,...,bn。
相邻整数之间用单个空格隔开。每个整数的绝对值都不超过1000。
输出
一个整数,即两个向量的点积结果。
样例输入
3 1 4 6 2 1 5
样例输出
36
要计算两个n维向量的点积,可以按照以下步骤实现:
- 读取输入的整数n,它表示向量的维度。
- 读取两个n维向量a和b的元素。
- 计算向量a和b的点积,即每个对应元素的乘积之和。
- 输出计算结果。
下面是Python代码的实现:
def dot_product(n, vector_a, vector_b): # 初始化点积结果 result = 0 # 计算点积 for i in range(n): result += vector_a[i] * vector_b[i] return result # 读取输入 n = int(input().strip()) vector_a = list(map(int, input().strip().split())) vector_b = list(map(int, input().strip().split())) # 计算并输出结果 print(dot_product(n, vector_a, vector_b))
解释
- 读取输入:
- 第一行读取整数n,表示向量维度。
- 第二行读取n个整数构成向量a。
- 第三行读取n个整数构成向量b。
- 计算点积:
- 初始化一个变量
result
为0,用于存储点积结果。- 使用一个循环遍历向量a和b的每一个元素,将对应元素的乘积累加到
result
中。- 输出结果:
- 打印计算得到的点积结果。
044:病人排队
描述
病人登记看病,编写一个程序,将登记的病人按照以下原则排出看病的先后顺序:
1. 老年人(年龄 >= 60岁)比非老年人优先看病。
2. 老年人按年龄从大到小的顺序看病,年龄相同的按登记的先后顺序排序。
3. 非老年人按登记的先后顺序看病。
输入
第1行,输入一个小于100的正整数,表示病人的个数;
后面按照病人登记的先后顺序,每行输入一个病人的信息,包括:一个长度小于10的字符串表示病人的ID(每个病人的ID各不相同且只含数字和字母),一个整数表示病人的年龄,中间用单个空格隔开。
输出
按排好的看病顺序输出病人的ID,每行一个。
样例输入
5 021075 40 004003 15 010158 67 021033 75 102012 30
样例输出
021033 010158 021075 004003 102012
问题分析
我们需要根据病人的年龄和登记顺序来确定他们看病的优先级:
老年人(年龄 >= 60 岁)优先。
老年人按年龄从大到小排序,年龄相同的按登记顺序排序。
非老年人按登记顺序排序。
解决思路
输入处理:读取病人数量,然后依次读取每个病人的ID和年龄,并记录他们的登记顺序。
分类病人:将病人分为老年人和非老年人两类。
排序处理:
对老年人按年龄降序排序,年龄相同的按登记顺序升序排序。
非老年人按登记顺序排序。
合并结果:将排序后的老年人和非老年人合并,输出结果。
解决代码
# 读取病人数量 n = int(input()) # 存储病人信息,格式为 (年龄, 登记顺序, ID) patients = [] for i in range(n): patient_id, age = input().split() age = int(age) patients.append((age, i, patient_id)) # 分类:老年人和非老年人 seniors = [p for p in patients if p[0] >= 60] non_seniors = [p for p in patients if p[0] < 60] # 对老年人排序:年龄降序,登记顺序升序 seniors_sorted = sorted(seniors, key=lambda x: (-x[0], x[1])) # 非老年人按登记顺序排序 non_seniors_sorted = sorted(non_seniors, key=lambda x: x[1]) # 合并结果 result = seniors_sorted + non_seniors_sorted # 输出病人ID for p in result: print(p[2])
代码解释
输入处理:
读取病人数量
n
。使用循环读取每个病人的ID和年龄,并记录登记顺序
i
,存储为元组(年龄, 登记顺序, ID)
。分类病人:
使用列表推导式将病人分为老年人(
age >= 60
)和非老年人(age < 60
)。排序处理:
对老年人按年龄降序排序,年龄相同的按登记顺序升序排序。
非老年人按登记顺序排序。
合并结果:
将排序后的老年人和非老年人列表合并。
输出结果:
遍历合并后的列表,输出每个病人的ID。
复杂度分析
时间复杂度:排序的时间复杂度为 O(nlogn)O(nlogn),其中 nn 是病人数量。
空间复杂度:使用了额外的空间存储分类后的列表,空间复杂度为 O(n)O(n)。
045:矩阵乘法
描述
计算两个矩阵的乘法。n*m阶的矩阵A乘以m*k阶的矩阵B得到的矩阵C 是n*k阶的,且C[i][j] = A[i][0]*B[0][j] + A[i][1]*B[1][j] + …… +A[i][m-1]*B[m-1][j](C[i][j]表示C矩阵中第i行第j列元素)。
输入
第一行为n, m, k,表示A矩阵是n行m列,B矩阵是m行k列,n, m, k均小于100
然后先后输入A和B两个矩阵,A矩阵n行m列,B矩阵m行k列,矩阵中每个元素的绝对值不会大于1000。
输出
输出矩阵C,一共n行,每行k个整数,整数之间以一个空格分开。
样例输入
3 2 3 1 1 1 1 1 1 1 1 1 1 1 1
样例输出
2 2 2 2 2 2 2 2 2
矩阵乘法的实现可以通过嵌套循环来完成。具体步骤如下:
输入矩阵A和矩阵B的维度:首先读取输入的n, m, k,表示矩阵A是n行m列,矩阵B是m行k列。
输入矩阵A和矩阵B的元素:分别读取矩阵A和矩阵B的元素。
计算矩阵C:矩阵C的第i行第j列的元素C[i][j]等于矩阵A的第i行与矩阵B的第j列的点积。
输出矩阵C:按照要求输出矩阵C的元素。
# 读取输入的n, m, k n, m, k = map(int, input().split()) # 初始化矩阵A和矩阵B A = [] B = [] # 读取矩阵A for i in range(n): row = list(map(int, input().split())) A.append(row) # 读取矩阵B for i in range(m): row = list(map(int, input().split())) B.append(row) # 初始化矩阵C,大小为n行k列,初始值为0 C = [[0 for _ in range(k)] for _ in range(n)] # 计算矩阵乘法 for i in range(n): for j in range(k): for l in range(m): C[i][j] += A[i][l] * B[l][j] # 输出矩阵C for i in range(n): print(" ".join(map(str, C[i])))
代码解释:
输入部分:
首先读取n, m, k的值。
然后分别读取矩阵A和矩阵B的元素,并存储在二维列表A和B中。
矩阵乘法计算:
初始化一个大小为n行k列的矩阵C,所有元素初始值为0。
通过三重循环计算矩阵C的每个元素C[i][j],即矩阵A的第i行与矩阵B的第j列的点积。
输出部分:
遍历矩阵C的每一行,输出该行的元素,元素之间用空格分隔。
复杂度分析:
时间复杂度:O(n * m * k),因为有三重循环。
空间复杂度:O(n * k),用于存储结果矩阵C。
046:回文子串
描述
给定一个字符串,输出所有长度至少为2的回文子串。
回文子串即从左往右输出和从右往左输出结果是一样的字符串,比如:abba,cccdeedccc都是回文字符串。
输入
一个字符串,由字母或数字组成。长度500以内。
输出
输出所有的回文子串,每个子串一行。
子串长度小的优先输出,若长度相等,则出现位置靠左的优先输出。
样例输入
123321125775165561
样例输出
33 11 77 55 2332 2112 5775 6556 123321 165561
这个问题要求我们找出字符串中所有长度至少为2的回文子串,并按照一定的顺序输出:先按长度排序,如果长度相等则按出现位置排序。
解决思路:
- 回文子串的定义:回文字符串是正着读和反着读都一样的字符串。
- 子串生成:我们可以通过遍历字符串的所有可能的起始和结束位置来获取所有的子串。
- 判断回文:对于每个子串,我们判断它是否是回文字符串。
- 去重和排序:我们可以使用一个集合来去重,并根据题目要求的排序规则(先按长度,若长度相同则按出现位置)进行排序。
具体实现步骤:
- 遍历字符串的所有可能子串(长度从2到n)。
- 判断每个子串是否为回文。
- 将回文子串存入集合,避免重复。
- 将所有回文子串按照长度和出现位置排序并输出。
Python实现:
def is_palindrome(s): return s == s[::-1] # 判断字符串是否是回文 def find_palindromic_substrings(s): n = len(s) result = [] # 遍历所有子串 for length in range(2, n+1): # 子串长度从2开始 for start in range(n - length + 1): substring = s[start:start+length] if is_palindrome(substring): result.append((length, start, substring)) # 保存回文子串的长度、起始位置和子串 # 按照长度和起始位置排序 result.sort() return [item[2] for item in result] # 输入 s = input().strip() # 查找回文子串 palindromes = find_palindromic_substrings(s) # 输出结果 for palindrome in palindromes: print(palindrome)
代码解释:
is_palindrome
函数判断一个字符串是否为回文。find_palindromic_substrings
函数用于找出所有的回文子串,并返回按照指定顺序排序后的回文子串列表。- 主程序中首先读取输入字符串,然后调用
find_palindromic_substrings
获取回文子串列表,最后逐行输出。时间复杂度:
- 枚举所有子串的时间复杂度是O(n^2)。
- 每个子串的回文判定是O(k),其中k是子串的长度,因此回文检查的时间复杂度是O(n^3)。
- 排序的时间复杂度是O(n^2 log n)(最多会有n^2个回文子串)。
因此总体的时间复杂度为O(n^3),对于n最大为500的情况是可以接受的。
047:校园食宿预订系统
描述
某校园为方便学生订餐,推出食堂预定系统。食宿平台会在前一天提供菜单,学生在开饭时间前可订餐。 食堂每天会推出m个菜,每个菜有固定的菜价和总份数,售卖份数不能超过总份数。 假设共有n个学生点餐,每个学生固定点3个菜,当点的菜售罄时, 学生就买不到这个菜了。 请根据学生预定记录,给出食堂总的预定收入 数据满足1 <= n <= 6000,3 <= m <= 6000,单品菜价不大于1000元,每个菜的配额不超过3000
输入
第一行两个整数n和m,代表有n个学生订餐,共有m个可选的菜
下面m行,每行三个元素,分别是菜名、售价和可提供量,保证菜名不重合,菜价为整数
下面n行,每行三个元素,表示这个学生点的三个菜的菜名
输出
一个整数,表示食堂的收入
样例输入
5 5 yangroupaomo 13 10 jituifan 7 5 luosifen 16 3 xinlamian 12 20 juruo_milktea 999 1 yangroupaomo luosifen juruo_milktea luosifen xinlamian jituifan yangroupaomo jituifan juruo_milktea jituifan xinlamian luosifen yangroupaomo yangroupaomo yangroupaomo
样例输出
1157
提示
如果用python做,要用字典,
如果用其它语言做,也要用类似的数据结构
否则会超时
名字长度范围没有给出,长度不会太离谱。请自己选用合适的办法确保这不是个问题这个问题要求我们模拟学生点餐和食堂的售卖过程,并计算最终的食堂收入。题目给定了每个菜的售价和可提供的数量,学生每次点餐会选择3个菜,若某个菜售罄,则学生无法再选择该菜。
解决思路:
输入解析:首先需要读取学生数、菜品数、每个菜品的名字、价格和数量,以及每个学生的点餐记录。
菜品管理:维护一个字典,用来存储每个菜品的价格和剩余数量。菜品的售卖数量一旦达到上限,就不能再提供。
收入计算:遍历每个学生的点餐记录,如果学生点的菜还未售罄,扣除相应的份额并计算收入。如果某个菜已经售罄,则不计算该菜的收入。
输出结果:最后输出总的收入。
具体步骤:
读取菜品信息并存储在一个字典中,键是菜名,值是一个元组
(价格, 剩余数量)
。遍历每个学生的点餐记录,检查菜品是否有剩余,若有,则计算收入并减少对应菜品的剩余数量。
在遍历过程中,若菜品售罄,则该菜不再参与收入计算。
Python实现:
def main(): # 读取学生数 n 和菜品数 m n, m = map(int, input().split()) # 用字典存储菜品的信息,键是菜名,值是 (价格, 剩余数量) menu = {} # 读取 m 道菜的信息 for _ in range(m): dish, price, quantity = input().split() menu[dish] = [int(price), int(quantity)] # 初始化总收入 total_income = 0 # 处理每个学生的点餐记录 for _ in range(n): dishes = input().split() # 存储当前学生的收入 student_income = 0 for dish in dishes: # 检查当前菜品是否还有剩余 if menu[dish][1] > 0: # 如果剩余数量大于0 student_income += menu[dish][0] # 加上菜品的价格 menu[dish][1] -= 1 # 该菜品剩余量减1 # 将该学生的收入加入总收入 total_income += student_income # 输出总收入 print(total_income) if __name__ == "__main__": main()
代码解释:
输入解析:使用
map(int, input().split())
读取n
和m
,并用字典menu
存储菜品信息,菜名作为键,菜品的价格和剩余数量作为值(列表形式)。学生点餐处理:遍历每个学生的点餐记录,每个学生点3个菜。对于每个菜,检查菜品的剩余数量是否大于0。如果是,学生可以购买该菜并更新菜品的剩余数量,计算并累计收入。
输出总收入:在所有学生的点餐处理完成后,输出食堂的总收入。
解释:
第1个学生:点了
yangroupaomo
,luosifen
,juruo_milktea
,收入13 + 16 + 999 = 1028
,剩余量分别变为(9, 2, 0)
。第2个学生:点了
luosifen
,xinlamian
,jituifan
,收入16 + 12 + 7 = 35
,剩余量变为(2, 4, 4)
。第3个学生:点了
yangroupaomo
,jituifan
,juruo_milktea
,收入13 + 7 + 999 = 1028
,剩余量变为(8, 3, 0)
。第4个学生:点了
jituifan
,xinlamian
,luosifen
,收入7 + 12 + 16 = 35
,剩余量变为(2, 2, 2)
。第5个学生:点了
yangroupaomo
,yangroupaomo
,yangroupaomo
,收入13 + 13 + 13 = 39
,剩余量变为(5, 2, 2)
。最终的总收入是
1028 + 35 + 1028 + 35 + 39 = 1157
。时间复杂度:
处理菜品信息是O(m)。
处理每个学生的点餐信息是O(n),每个学生有3个菜需要检查,所以总时间复杂度是O(n)。
所以总体时间复杂度是O(n + m),对于最大输入大小来说是可以接受的。