python高阶函数求连乘_高阶函数三板斧

# 高阶函数三板斧

以函数为参数或者返回值的函数又称为高阶函数。高阶函数能以非常简洁的方式实现很多令人拍案的操作。但是,要把高阶函数的效果充分用出来还是需要一定基础的。作为一个新手,怎么快速利用高阶函数技巧,精简代码,提升自己的效率呢?

恰好,在函数式编程中,有这么三个高阶函数。虽然它们并不是理论上最根基的函数,但是在处理线性结构的时候十分好用。即使刚刚接触函数式的新手也能快速上手马上应用到自己的代码中。这就是`map`,`filter`和`reduce`(这三个函数都是接收一个线性表和一个函数作为参数)。这三个函数就和程咬金三板斧类似,简单,有效。下面我们一一介绍。

## 切西瓜——map

`map`的返回值是一个和输入线性表等长的线性表。由于输入的表和输出的表在长度上对称,我把它比喻成“切西瓜”。

`map`接受一个函数`f`和一个线性结构`L`作为输入。返回一个线性结构`M`。其中`M`的每个成员相当于把`f`作用到`L`中对应位置成员上所得的返回值。举个例子,你有100个自变量的值,和一个函数`f`,要求出`f`在这100个自变量上的函数值。就可以用`map`来实现。

Python中`map`是个内建函数。我们直接调用就可以。不过注意,Python中`map`的返回值是个可迭代对象,需要用`list`函数转换成列表。

```python

def f(x):

return x**2

L=[1,20,31,4,2]

M=list(map(f,L))

print(L)

print(M)

```

顺便说一句,这个`map`的功能是不是有点眼熟呢?没错,就是上次我们写的那个`calcList`函数。

## 鬼剔牙——filter

`filter`关键在于一个“剔”字。它也接受一个函数`f`和`L`作为输入。不过这个`f`应当以`L`中的成员为输入,然后以一个逻辑值为输出。`filter`选择让`f`输出`True`的对象,组成一个新列表,然后返回。

例如选出一个列表中所有大于5的数字(结果同样需要`list`转换)。

```python

def f(x):

return x>5

L=[1,20,31,4,2]

M=list(filter(f,L))

print(L)

print(M)

```

## 掏耳朵——reduce

`reduce`是个细致活。它也要遍历整个列表,但是它最后返回的不是一个列表,而是一个对象(当然你也可以把一个列表当一个对象返回)。

`reduce`接受一个函数`f`和一个线性结构`L`作为输入。`f`接受两个对象作为输入,返回一个对象作为结果。

`reduce`把`L`开头两个成员输入`f`然后,把所得结果和`L`中下一个对象再一起输入`f`。如此往复直到只剩一个结果,然后返回这个结果。(如果`L`中只有一个成员则直接返回这个成员。)

`reduce`可以用来处理连加,连乘,统计总数,把多个字符串聚合成一个字符串等。这里简单举个例子(Python中`reduce`不是内建函数,需要从标准库`functools`导入):

```python

from functools import reduce

def f(x,y):

return x*y

L=[1,20,31,4,2]

M=reduce(f,L)

print(L)

print(M)

```

其实连加(`sum`),求最大值(`max`),求最小值(`min`)这些函数Python中已经提供了内建函数版,需要的时候可以直接调用。

如果想的话也可以用`reduce`自己实现。这里再举一个求最大值的例子:

```python

from functools import reduce

def f(x,y):

if(x>=y):

return x

else:

return y

L=[1,20,31,4,2]

M=reduce(f,L)

print(L)

print(M)

```

顺便说一句,实数的加法,乘法,比大小运算都是满足交换律的。对于不满足交换律的运算,其实`reduce`还可以分从左往右或者从右往左两个版本。不过这些都是比较细节的讨论了。把`reduce`分两个版本也不是很必要,如果真的需要用从右往左的运算,可以配合列表逆序排列函数来使用`reduce`。

## 剩下半招

三板斧确实很猛,但是别急,Python中还有一些辅助性的功能能让三板斧如虎添翼。

内建函数`zip`能把两个线性表打包成一个线性表(对应位置的成员按顺序打包成元组)。举个例子,可以用它配合`filter`完成列表的比对,返回有差异的地方。

```python

def f(x):

return x[0]!=x[1]

L1=[1,20,31,4,2]

L2=[1,21,30,4,2]

L=zip(L1,L2)

M=list(filter(f,L))

print(M)

```

如果你的操作和列表成员的索引有关,那么可以用内建函数`enumerate`。它和`zip`类似,不过它是把一个链表和自身的索引打包起来。比如筛选所有索引为偶数的项目:

```python

def f(x):

return x[0]%2==0

L=['a','b','c','d','e']

L=enumerate(L)

M=list(filter(f,L))

print(M)

```

需要注意的是`zip`和`enumerate`返回的都是列表,而是可迭代对象。如果需要直接查看它们的结果,可以用`list`函数转换类型。

## 关于Lambda

如果你正好学了学Python的lambda表达式,那么写起代码来会更加简洁。之前我故意不用lambda表达式,是为了降低代码阅读门槛。

> 顺便澄清一个问题:不是有lambda表达式才叫函数式编程,只要能把函数当参数传递。就和函数式沾边了。

这里我们用lambda表达式改写一段代码,把切西瓜那一节的源码用lambda表达式改写后可以非常短(删掉了一些和输入输出有关的代码):

```python

M=list(map(lambda x: x**2,L))

```

## 小结

不管你对纯函数编程的态度如何,用高阶函数优化线性结构处理代码的效果你都看到了。很多情况下根本不需要用循环,而且代码还超级简洁。

再次重申,这些技巧不只是Python中可以用。就算是C,我们也能创造条件使用这些技巧。

> Python很讨厌的一点就是很多拓展库都喜欢带自己的数据结构,而不老老实实使用Python的数据结构。这就导致有时候Python的高阶函数不能在一些拓展库的数据结构上使用。

>

> 好在这些拓展库多少也自带高阶函数。比如pandas的`pandas.Series.map`,numpy的`numpy.apply_along_axis`,torch的`torch.Tensor.map_`

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值