今天和大家聊一聊Python 中的高阶函数:map、reduce、filter、sorted
首先了解一下什么是高阶函数,
高阶函数 就是让函数的参数能够接受别的函数,比如:
1 defadd(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 defadd_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 deff_double(x):2 return 2 *x3
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 函数返回的是一个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 defmultiple(x, y):4 return x * 10 +y5
6 from functools importreduce7 list1 = [1, 3, 5, 7, 9]8 r =reduce(multiple, list1)9 print(r) #13579
这个例子本身没多大用处,但是考虑到字符串str 也是一个序列,对上面的例子稍加改动,配合map()
就可以写出str 转换为int 的函数:
1 from functools importreduce2
3 DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4,4 '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}5 defmultiple(x, y):6 return x * 10 +y7
8 defchar2num(s):9 returnDIGITS[s]10
11 r = reduce(multiple, map(char2num, '2468'))12 print(r) # 2468
下面是廖老师出的几个问题,同学们可以思考一下,并参考一下我这边给出的代码,看看还有没有什么可以优化,或者我没考虑的地方,欢迎留言指导~
Q1.综合写一个不借助int() 函数,将字符串转换成数字的方法:
1 from functools importreduce2
3 DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4,4 '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}5 defstr2num(s):6 m = map(lambdax: DIGITS[x], s)7 try:8 r = reduce(lambda x, y: x*10+y, m)9 exceptKeyError:10 print('请输入纯数字的字符串!')11 else:12 returnr13
14 result = str2num('3234cc4')15 print(type(result))16 print(result)17
18 #请输入纯数字的字符串!
19 #
20 #None
21
22 result2 = str2num('32344')23 print(type(result2))24 print(result2)25
26 #
27 #32344
Q1
Q2.利用map() 函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写
1 defnormalize(name):2 try:3 if notname.isalpha():4 return
5 exceptAttributeError:6 print("您输入的:{} 不是正确的姓名".format(name))7 else:8 returnname.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) ifx]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
1 defstr2float(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_res6
7 defsplit_int_float(s):8 #以小数点为分隔区,返回整数部分和小数部分
9 str_int, str_float = s.split('.')[0], s.split('.')[1]10 returnstr_int, str_float11
12 defchar2num(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 importreduce15 num = reduce(lambda x, y:x*10+y, map(lambdax:DIGITS[x], char))16 returnnum17
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 defnot_empty(s):2 try:3 s.strip()4 exceptAttributeError:5 print('请输入字符串')6 else:7 return s ands.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 defis_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