一、先拆开那行“天书代码”
这种代码,盯着看了半天,怀疑自己学的 Python 是假的:
list(map(lambda x: x[0], filter(lambda p: p[0] == p[1], zip(A, B))))
假设:
A = [1, 2, 3, 4]B = [1, 0, 3, 5]
目标:取出 A、B 对应位置相同的值。
这行代码等价于:
[a for a, b in zip(A, B) if a == b]# [1, 3]
第 1 层:zip(A, B)把两个列表配对。
list(zip(A, B))# [(1, 1), (2, 0), (3, 3), (4, 5)]
第 2 层:filter(lambda p: p[0] == p[1], ...)只保留对应位置相等的配对。
# 相当于只保留 (1,1) 和 (3,3)
第 3 层:map(lambda x: x[0], ...)取出每个元组的第 0 个元素。
# 得到 1, 3
第 4 层:list(...)把 map 的结果转成列表。
[1, 3]
一句话总结:先配对,再筛选相同的,再取第一个值,最后转成列表。
三、lambda 到底是什么?
1. 它就是一个“匿名函数”
def add(x, y): return x + y# 等价写法lambda x, y: x + y
2. lambda 本身不会自动执行
f = lambda x: x * 2f(3) # 6
3. lambda 适合写什么?
适合一行能写完的简单逻辑,不适合复杂业务。
lambda x: x * 2lambda p: p[0] == p[1]lambda s: len(s)
四、map 和 filter 原理讲透
1. filter(function, iterable)
作用:过滤
nums = [1, 2, 3, 4, 5]list(filter(lambda x: x % 2 == 0, nums))# [2, 4]
等价 for 逻辑:
result = []for x in nums: if x % 2 == 0: result.append(x)
2. map(function, iterable)
作用:映射 / 转换
nums = [1, 2, 3]list(map(lambda x: x * 2, nums))# [2, 4, 6]
等价 for 逻辑:
result = []for x in nums: result.append(x * 2)
笔试核心:map / filter 本质上都是“对一个可迭代对象,逐个元素应用某个函数”。这和 for 是一回事,只是写法更函数式。
五、为什么有的 lambda 前面是 [,有的是 (?
1. ( 包起来:通常是在调用工具函数
map(lambda x: x * 2, nums)filter(lambda x: x > 0, nums)sorted(nums, key=lambda x: x[1])
这里的 ( 是函数调用的括号,不是 lambda 专属。
2. [ 包起来:通常是列表推导式
[x * 2 for x in nums][x for x in nums if x > 0]
这和 lambda 没有直接关系,是另一种写循环的方式。
3. 记忆口诀
- 看到
map(...) / filter(...):外面是圆括号 ( - 看到
[... for ... in ...]:外面是方括号 [ lambda
六、map / filter 和 for 到底什么关系?
它们不是对立关系,而是同一种逻辑的两种写法。
# 函数式写法list(map(lambda x: x * 2, filter(lambda x: x % 2 == 0, nums)))# for 写法result = []for x in nums: if x % 2 == 0: result.append(x * 2)# 列表推导[x * 2 for x in nums if x % 2 == 0]
考场建议:如果题目考“输出结果”,脑子里先翻译成 for,基本就不会错。
七、除了这几个,笔试还经常考谁?
1. zip — 配对
A = [1, 2, 3]B = ['a', 'b', 'c']list(zip(A, B))# [(1, 'a'), (2, 'b'), (3, 'c')]
2. enumerate — 同时拿索引和值
for i, v in enumerate(['a', 'b', 'c']): print(i, v)
3. sorted(key=...) — 按规则排序
pairs = [(1, 5), (2, 1), (3, 3)]sorted(pairs, key=lambda x: x[1])# [(2, 1), (3, 3), (1, 5)]
4. reduce — 把多个值归并成一个
from functools import reducereduce(lambda x, y: x + y, [1, 2, 3, 4])# 10reduce(lambda x, y: x + y, [[1,2], [3,4], [5,6]], [])# [1, 2, 3, 4, 5, 6]
5. any / all
any([False, False, True]) # Trueall([True, True, False]) # Falseany(x > 0 for x in [-1, -2, 3])
6. 列表推导 / 生成器表达式
[x * 2 for x in nums if x > 0] # 列表(x * 2 for x in nums if x > 0) # 生成器
八、这类题的通用拆解法
- 找最内层数据源
- 判断是筛选还是转换:有 if 想 filter;元素变一下想 map
- 翻译成 for
- 再翻回函数式写法
result = []for ... in ...: if ...: result.append(...)
九、笔试高频坑位
坑 1:map / filter 返回的不是列表
map(lambda x: x * 2, [1, 2, 3]) # map 对象list(map(lambda x: x * 2, [1, 2, 3])) # [2, 4, 6]
坑 2:lambda 里写错 = 和 ==
lambda x, y: x == y # 比较,正确lambda x, y: x = y # 赋值,错误
坑 3:sorted 和 sort
sorted(lst) # 返回新列表lst.sort() # 原地修改,返回 None
坑 4:sum 的第二个参数类型要匹配
sum([[1,2], [3,4]], []) # 可以sum(['1', '33'], []) # 报错
坑 5:列表推导不是 lambda
[lambda x: x*2 for x in nums] # 得到一堆函数,错误[x*2 for x in nums] # 正确
十、常考题对比
题 1:取偶数
list(filter(lambda x: x % 2 == 0, nums))[x for x in nums if x % 2 == 0]
题 2:每个元素平方
list(map(lambda x: x ** 2, nums))[x ** 2 for x in nums]
题 3:A、B 相同位置的相同值
list(map(lambda p: p[0], filter(lambda p: p[0] == p[1], zip(A, B))))[a for a, b in zip(A, B) if a == b]
题 4:按第二个元素排序
sorted(pairs, key=lambda x: x[1])
题 5:列表扁平化
reduce(lambda x, y: x + y, [[1,2],[3,4]], [])[x for sub in lst for x in sub]
十一、面试时怎么答更加分?
如果面试官问:map / filter 和列表推导有什么区别?
- map / filter 返回迭代器,列表推导直接生成列表
加分回答:我看到 map / filter / lambda 时,会先在脑子里翻译成 for,这样最不容易错。
十二、考场速查表
| |
|---|
| for x in lst |
| [x for x in lst if 条件] |
| [f(x) for x in lst] |
| zip(A, B) |
| enumerate(lst) |
| sorted(lst, key=...) |
| reduce(func, lst, init) |
| any(...) |
十三、真正要记住的一句话
lambda 不是魔法,只是临时小函数;map 是批量加工,filter 是批量筛选,for 是它们的底层逻辑。
所以以后看到这行代码:
list(map(lambda x: x[0], filter(lambda p: p[0] == p[1], zip(A, B))))
别慌,直接翻译成:
result = []for a, b in zip(A, B): if a == b: result.append(a)
你就已经会了。