函数式编程filter、map、reduce

函数式编程filter、map、reduce

(本文是一篇学习笔记和自己对filter、map、reduce的理解
参考:link.
作为一名半路出家的程序员,还记得第一门学习的编程语言是C,那种面向过程设计的语言风格很适合做事的流程和方式,很容易让人上手。但是C 语言虽然简单灵活,能够让程序员在高级语言特性之上轻松进行底层上的微观控制,被誉为“高级语言中的汇编语言”,但其基于过程和底层的设计初衷又成了它的短板(例如内存的申请释放完全由程序员控制,这就会带来很多的意外惊喜)。
后面慢慢接受到了面向对象的程序设计,学习了C++,Java,Python等语言,逐渐感受到对象化对于编程的优势,面向对象编程不够友好地就是代码阅读体验不佳,因为很多方法都封装在了接口或者类里面,对其行为不仔细阅读代码有时不是很好把握,但或许这就是万物皆对象的魅力所在吧。
最近接触了一点点函数式编程。

什么是函数式编程?

学习过数学应该都知道函数,如:

f(x)=5x^2+4x+3
g(x)=2f(x)+5=10x^2+8x+11
h(x)=f(x)+g(x)=15x^2+12x+14

假设 f(x) 是一个函数,g(x) 是第二个函数,把 f(x) 这个函数套下来,并展开。然后还可以定义一个由两个一元函数组合成的二元函数,还可以做递归,下面这个函数定义就是斐波那契数列。

f(x)=f(x-1)+f(x-2)

对于函数式编程来说,它只关心定义输入数据和输出数据相关的关系,数学表达式里面其实是在做一种映射(mapping),输入的数据和输出的数据关系是什么样的,是用函数来定义的
函数式编程有以下特点。特征
stateless:函数不维护任何状态。函数式编程的核心精神是 stateless,简而言之就是它不能存在状态,打个比方,你给我数据我处理完扔出来。里面的数据是不变的。
immutable:输入数据是不能动的,动了输入数据就有危险,所以要返回新的数据集。
优势
没有状态就没有伤害。
并行执行无伤害。
Copy-Paste 重构代码无伤害。
函数的执行没有顺序上的问题。

函数式编程也很简单容易,例如:
// 非函数式,不是pure funciton,有状态
int cnt;
void increment(){
    cnt++;
}

// 函数式,pure function, 无状态
int increment(int cnt){
    return cnt+1;
}

为什么需要函数式编程?

编程语言是一种工具,编程语言的发展也是朝着越来越高效,方便的路径发展。随着各种语言的出现,程序员已经不再局限于各种语言,而是聚焦于业务,这就要求程序具有抽象的能力,能解决通用问题,这就是编程范式。
在程序世界中,编程工作更多的是解决业务上的问题,而不是计算机的问题,我们需要更为贴近业务、更为抽象的语言,如典型的面向对象语言 C++ 和 Java 等。
函数式编程的理念:
把函数当成变量来用,关注描述问题而不是怎么实现,这样可以让代码更易读。
因为函数返回里面的这个函数,所以函数关注的是表达式,关注的是描述这个问题,而不是怎么实现这个事情。

函数式编程关注的是:describe what to do, rather than how to do it
过程式编程范式叫做 Imperative Programming – 指令式编程,而把函数式编程范式叫做 Declarative Programming – 声明式编程

函数式语言的三套件

函数式语言有三套件,Map、Reduce 和 Filter,在学习得时候理解不是很好,在此记录几个例子复习一下。

Map

map() 会根据提供的函数对指定序列做映射。

第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。

# 传统的非函数式
upname =['HAO', 'CHEN', 'COOLSHELL']
lowname =[] 
for i in range(len(upname)):
    lowname.append( upname[i].lower() )

# 函数式
def toUpper(item):
      return item.upper()
 
upper_name = map(toUpper, ["hao", "chen", "coolshell"])

print(upper_name)
# 输出 ['HAO', 'CHEN', 'COOLSHELL']

map(lambda x: x ** 2, [1, 2, 3, 4, 5])  # 使用 lambda 匿名函数

reduce

reduce() 函数会对参数序列中元素进行累积。

函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。[reduce是减少的意思,每次头用函数合并前两个数据,知道集合中只有一个数据为止]

from functools import reduce

def add(x, y) :            # 两数相加
    return x + y
sum1 = reduce(add, [1,2,3,4,5])   # 计算列表和:1+2+3+4+5
sum2 = reduce(lambda x, y: x+y, [1,2,3,4,5])  # 使用 lambda 匿名函数

Filter

filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,然后返回 True 或 False,最后将返回 True 的元素放到新列表中

import math
def is_sqr(x):
    return math.sqrt(x) % 1 == 0
 
newlist = filter(is_sqr, range(1, 101))
print(newlist)

a = filter(lambda x: x % 2 == 0, range(10))

Map、Reduce 和 Filter是轮子,可以合起来造汽车:
计算数组中正数的平均值

# 计算数组中正数的平均值
num =  [2, -5, 9, 7, -2, 5, 3, 1, 0, -3, 8]
positive_num_cnt = 0
positive_num_sum = 0
for i in range(len(num)):
    if num[i] > 0:
        positive_num_cnt += 1
        positive_num_sum += num[i]
 
if positive_num_cnt > 0:
    average = positive_num_sum / positive_num_cnt
 
print(average)


#计算数组中正数的平均值
positive_num = list(filter(lambda x: x>0, num))  #python2返回事list,python2返回时filter对象,需要转换
average = reduce(lambda x,y: x+y, positive_num) / len( positive_num )

函数式编程的抽象:把业务抽象为一个个函数:
例如:把一个列表中偶数*3并转为字符串输出

def even_filter(nums):
    for num in nums:
        if num % 2 == 0:
            yield num
def multiply_by_three(nums):
    for num in nums:
        yield num * 3
def convert_to_string(nums):
    for num in nums:
        yield 'The Number: %s' % num

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 三个函数串起来
pipeline = convert_to_string(multiply_by_three(even_filter(nums)))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值