Python 高阶函数map、reduce、filter、sorted

时间:2021-07-27 02:21:46

今天和大家聊一聊Python 中的高阶函数:map、reduce、filter、sorted
首先了解一下什么是高阶函数,

高阶函数 就是让函数的参数能够接受别的函数,比如:

1 def add(x, y, f):
2     return f(x) + f(y)
3 
4 result = add(-5, 6, abs)
5 print(result)           # 11

再比如:

1 list1 = [1, 2, 3, 4, 5, 6]
2 list2 = [32, 11, 55, 46, 89, 43]
3 def add_total(l1, l2, fun):
4     return fun(l1) + fun(l2)
5  
6 result = add_total(list1, list2, min)
7 print(result)          # 12
8 result = add_total(list1, list2, max)
9 print(result)          # 95

那么Python 中这些高阶函数具体的作用是什么呢?不要着急,往下面看看

一、map 函数,接受两个参数,一个是函数,另一个是迭代对象Iterable ,将迭代对象Iterable 里面的每个元素作用到这个函数里面后,生成新的map 对象(是迭代器对象Iterator),并返回,比如:

1  def f_double(x):
2       return 2 * x
3   
4 list1 = [1, 2, 3, 4, 5, 6]
5 m = map(f_double, list1)
6 # print(list(m))          # [2, 4, 6, 8, 10, 12]
7 print(m)          # <map object at 0x00000259F8CCE102>   注意这个map 函数返回的是一个map 对象,这个map 对象是一个迭代器对象,所以可以调用next() 函数,也可以去使用for 循环进行循环遍历
8 print(next(m))          # 2   注意,需要注释上面的print(list(m))并重新运行,否则会报StopIteration 的错误

 

二、reduce 函数, 和map 函数一样接受两个参数,第一个是函数,第二个是序列Iterable ,不同是reduce 把结果继续和序列的下一个元素做累积运算,效果如下:

1 # reduce(fn, [x1, x2, x3, x4]) = fn(fn(fn(x1, x2), x3), x4)
2 
3 def multiple(x, y):
4     return x * 10 + y
5 
6 from functools import reduce
7 list1 = [1, 3, 5, 7, 9]
8 r = reduce(multiple, list1)
9 print(r)           # 13579

这个例子本身没多大用处,但是考虑到字符串str 也是一个序列,对上面的例子稍加改动,配合map()
就可以写出str 转换为int 的函数:

 1 from functools import reduce
 2 
 3 DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, 
 4           '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
 5 def multiple(x, y):
 6     return x * 10 + y
 7 
 8 def char2num(s):
 9     return DIGITS[s]
10 
11 r = reduce(multiple, map(char2num, '2468'))
12 print(r)          # 2468

下面是廖老师出的几个问题,同学们可以思考一下,并参考一下我这边给出的代码,看看还有没有什么可以优化,或者我没考虑的地方,欢迎留言指导~

 

Q1.综合写一个不借助int() 函数,将字符串转换成数字的方法:

Python 高阶函数map、reduce、filter、sortedPython 高阶函数map、reduce、filter、sorted
 1 from functools import reduce
 2 
 3 DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4,
 4           '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
 5 def str2num(s):
 6     m = map(lambda x: DIGITS[x], s)
 7     try:
 8         r = reduce(lambda x, y: x*10+y, m)
 9     except KeyError:
10         print('请输入纯数字的字符串!')
11     else:
12         return r
13 
14 result = str2num('3234cc4')          
15 print(type(result))          
16 print(result)
17 
18 # 请输入纯数字的字符串!
19 # <class 'NoneType'>
20 # None
21 
22 result2 = str2num('32344')
23 print(type(result2))      
24 print(result2)
25 
26 # <class 'int'>
27 # 32344
Q1

 

Q2.利用map() 函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写

Python 高阶函数map、reduce、filter、sortedPython 高阶函数map、reduce、filter、sorted
 1 def normalize(name):
 2     try:
 3         if not name.isalpha():
 4             return
 5     except AttributeError:
 6         print("您输入的:{} 不是正确的姓名".format(name))
 7     else:
 8         return name.capitalize()
 9 # result = str(name).capitalize()
10 # return result
11 
12 L1 = ['adam', 'LISA', 'barT1', 123, 0, True, '123333', [23,11], (11, 33), "丽丽"]
13 L2 = [x for x in map(normalize, L1) if x]
14 print('你输入的最终姓名名单为:{}'.format(L2))
15 
16 
17 # 您输入的:123 不是正确的姓名
18 # 您输入的:0 不是正确的姓名
19 # 您输入的:True 不是正确的姓名
20 # 您输入的:[23, 11] 不是正确的姓名
21 # 您输入的:(11, 33) 不是正确的姓名
22 # 你输入的最终姓名名单为:['Adam', 'Lisa', '丽丽']
Q2

 

Q3.利用map 和reduce 编写一个str2float 的函数,比如把字符串‘123.456’ 转换成浮点数123.456

Python 高阶函数map、reduce、filter、sortedPython 高阶函数map、reduce、filter、sorted
 1 def str2float(s):
 2     i1, f1 = split_int_float(s)
 3     int_res = char2num(i1)
 4     float_res = char2num(f1) / 10**len(f1)
 5     return int_res + float_res
 6 
 7 def split_int_float(s):
 8     # 以小数点为分隔区,返回整数部分和小数部分
 9     str_int, str_float = s.split('.')[0], s.split('.')[1]
10     return str_int, str_float
11 
12 def char2num(char):
13     DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
14     from functools import reduce
15     num = reduce(lambda x, y:x*10+y, map(lambda x:DIGITS[x], char))
16     return num
17 
18 
19 print('str2float(\'123.456\') =', str2float('123.456'))
20 if abs(str2float('123.456') - 123.456) < 0.00001:
21     print('测试成功!')
22 else:
23     print('测试失败!')
24 
25 
26 # str2float('123.456') = 123.456
27 # 测试成功!
Q3

 

三、filter 函数 也是接收一个函数和一个序列,filter()把传入的函数作用于序列的每个元素,然后根据返回值是True 还是False 决定保留还是丢弃该元素

1.比如把一个序列中的非字符串删掉,可以这么写:

 1 def not_empty(s):
 2     try:
 3         s.strip()
 4     except AttributeError:
 5         print('请输入字符串')
 6     else:
 7         return s and s.strip()
 8 
 9 list_filter = list(filter(not_empty, ['A', '', 'B', None, 'C', ' ', 'B C', ' VV', 123]))
10 print(list_filter)          
11 
12 # 请输入字符串
13 # 请输入字符串
14 # ['A', 'B', 'C', 'B C', ' VV']

 

 

2.回数,值从左向右和从右向左读都是一样的数,如:12321,909,787,66266

1 def is_palindrome(n):
2     return str(n) == str(n)[::-1]
3 
4 # backnum = filter(is_palindrome, range(1, 100))
5 backnum = filter(lambda x: str(x) == str(x)[::-1], range(1, 100))
6 
7 print('1~100的回数为:', list(backnum))          # 1~100的回数为: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99]

 

四、sorted 函数,可以对list 进行排序:list 的元素,可以是数值,直接比较大小,也可以是字母,会按照ASCII 码比较

 

注意,sorted 函数和 列表的sort() 方法是有区别的

sorted(list1), 对list1 进行排序,并作为一个新的列表返回,list1 不变
ist1.sort(), 对list1 本身进行排序,改变的将是list1

 

前面说了sorted 函数也是一个高阶函数,它可以接收一个参数key 来实现自定义排序,key 的值是别的函数,或者是匿名函数。例如按照绝对值大小排序:

1 list4 = [-1, 9, -6, 55, 33, -5]
2 sort_list = sorted(list4)
3 abs_list = sorted(list4, key=abs)
4 print(sort_list)         # [-6, -5, -1, 9, 33, 55]
5 print(abs_list)          # [-1, -5, -6, 9, 33, 55]
6 
7 list5 = ['bob', 'about', 'Zoo', 'Credit']
8 res = sorted(list5)
9 print(res)          # ['Credit', 'Zoo', 'about', 'bob']

默认情况下,对字符串排序,是按照ASCII 的大小比较的,由于 在ASCII 中 'Z' < 'a', 所以‘Z’会排在‘a’前面

 

忽略大小写的做法:

1 list5 = ['bob', 'about', 'Zoo', 'Credit']
2 res_sort = sorted(list5, key=str.lower)
3 print(res_sort)          # ['about', 'bob', 'Credit', 'Zoo']

 

反序排序列,不必动用key 函数,可以传入第三个参数reverse=True,如:

1 list5 = ['bob', 'about', 'Zoo', 'Credit']
2 res_reverse_sort = sorted(list5, reverse=True)
3 ignore_reverse_sort = sorted(list5, key=str.lower, reverse=True)
4 print(res_reverse_sort)          # ['bob', 'about', 'Zoo', 'Credit']
5 print(ignore_reverse_sort)          # ['Zoo', 'Credit', 'bob', 'about']

 

sorted 函数的最最常用的场景,也是面试中经常会遇到的问题,给一个元素是元祖的列表按照元素第二个元素排序,或者是对一个字典的Value 进行排序,如下:

 1 D1 = {'Bob': 75, 'Adam': 92, 'Bart': 66, 'Lisa': 88}
 2 L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
 3 D2 = {'name': 'Lucy', 'age': 18, 'id': '110', 'sex': 'women'}
 4 print(sorted(L, key=lambda x: x[0].lower()))  # 按照人名排序,(不分大小写)
 5 print(sorted(D1.items(), key=lambda x: x[1]))  # 相当于先把D1 转换成L ,然后进行第7 行代码
 6 print(sorted(D2.items(), key=lambda x: x[0].lower()))  # 按照字典的K 排序,不分大小写
 7 print(sorted(L, key=lambda x: x[1]))  # 将L 按照成绩从小到大排序
 8 print(sorted(L, key=lambda x: -x[1]))  # 将L 按照成绩从大到小排列
 9 
10 
11 
12 [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]
13 [('Bart', 66), ('Bob', 75), ('Lisa', 88), ('Adam', 92)]
14 [('age', 18), ('id', '110'), ('name', 'Lucy'), ('sex', 'women')]
15 [('Bart', 66), ('Bob', 75), ('Lisa', 88), ('Adam', 92)]
16 [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]

至此,这四个Python 比较常用的高阶函数介绍完毕了,希望能给大家的学习带来一定的帮助

 

参考:高阶函数-廖雪峰的官方网站:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014317849054170d563b13f0fa4ce6ba1cd86e18103f28000