scala中的map函数与for中的yield

首先我们从scala的函数开始:

  在命令后输入:(x:Int) => x * 2

  这种奇怪的格式让我们陌生,但是如果你熟悉javascript的函数如下:

function myfunc(param){

   alert("hello" + param);

}

  这是一个弹出窗口hello的函数,显示的是hellp+输入参数,这个param不只是可以传入值,也可以传入另外一个函数,为了能够传入另外一个函数作为参数,被传入的函数在写法上要改变一下,比如:

var myfunc2 = function (param){

   alert("hello" + param);

}

  可以看到,我们将函数名称移到了左边,右边就剩余function和()以及{}三个符号,这样我们可以传入myfunc了:

myfunc(myfunc2);

  我们已经理解了JS中函数传递,那么Scala中也是类似,上面的(x:Int) => x * 2 其实可以看成JS的(x:Int) {  x * 2  } ,我们使用大括号替代右箭头=>,两者意思差不多(少一个function付)。等同于js:

var myfunc3 = function (x) {

  return   x * 2  ;

}

  scala的x:Int类似Java的Int x,Int是x的类型,js是动态语言,所以类型定义是不需要的。Scala的写法是:

var myfunc = (x:Int) => x * 2

  我们自己简写成(x:Int) => x * 2也可以,和myfunc一样到处引用使用,没有名称而已,也就是匿名函数,可以作为另外一个函数的输入参数使用。如:

myfunc2( (x:Int) => x * 2);

   myfunc这个函数自己也可以被直接使用:

myfunc(2)

结果是4;

  那么myfunc(myfunc(2))是多少呢,注意,这里不是myfunc2,而是myfunc自己。

myfunc(2)

结果是8; 相当于调用了两次自己。

   面向函数编程经常形象的比喻成类似集成电路的输入输出一样:

输入--->函数运算 -->输出

  所以,这里(x:Int) => x * 2也有这三种结构:

输入x---->函数运算x * 2 ---->输出x*2的结果。

  输出x*2结果和x*2运算实际是捆绑在一起,是一体的,所以,一般我们就不显式象js中声明return x*2。Scala的"=>"符号的 右边可以认为代表细节,代表函数体,代表ReturnValue is “右边”.

第二步

   有了前面热身,我们对函数是第一等公民有个初步印象,下面再看看函数如何作为值传递的:

val myList = List(1,2,3,4,5)

for(x:Int <- myList) yield myfunc (x)

  yield是专门用于for循环,将新的结果写入到结果序列中,这里将myfunc(x)结果返回一个新的List,结果是:List[Int] = List(2, 4, 6, 8, 10)

  下面我们引入面向函数编程最常用的一个函数map:

myList.map((x: Int) => x * 2)

结果也是List[Int] = List(2, 4, 6, 8, 10); 也相当以将集合myList中每个元素经过(x: Int) => x * 2运算得到结果。

   从输入输出这个角度理解这个函数map,map的输入是(x: Int) => x * 2的输出,而(x: Int) => x * 2的输入是什么呢?是x,那么x从哪里来的?猜测可能是来自myList的每个元素。

  这里引入一个函数组合子(Functional Combinators)定义,组合子是一个没有自由free变量的函数。什么叫自由变量?没有孤立的变量,比如上面的变量是x不应该是一个孤立变量,其来自于myList的元素。

  这里的map对列表myList中的每一个元素都应用了 x * 2函数,并返回一个新的列表List(2, 4, 6)。我们称这个操作是map 组合子,同理还有filter操作。

for(x <- c; if cond) yield {...}

  等同于:

c.filter(x => cond).map(x => {...})

  或

c.withFilter(x => cond).map(x => {...})

  

  注意到这里for中多了一个if语句判断,也就是对列表集合中元素进行if判断,这相当于使用了filter函数,filter对传入函数计算结果为false的全部删除。返回一个布尔值的函数通常被称为谓词函数[或判定函数]。

   再看看for的另外一种形式, 集合嵌套:

for(x <- c1; y <- c2; z <-c3) {...}

等同于:

c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))

  使用组合子foreach的好处这里也可以看出,使用for进行嵌套循环,经常可能会迷糊钻晕了,而使用组合子则简单明了。foreach 这个组合子类似Map,但是不返回任何结果,

val doubled = myList.foreach((x: Int) => x * 2)  
doubled: Unit = ()

  这里foreach返回结果为类型Unit,类似void,是空。

  flatMap 是另外一个组合子,flat可以理解为折叠或嵌套的意思。

for(x <- c1; y <- c2; z <- c3) yield {...}

等同于

c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))

  这里的for循环和上面区别多了一个yield,看到yield第一反应我们是想到map,但是这里集合不是一个,而是三个嵌套,那么我们就使用flat+map.注意到,z是嵌套集合最后一个输出,作为map的输入。

  再看一个例子,假设有嵌套集合如下:

 val nestedNumbers = List(List(1, 2), List(3, 4))
nestedNumbers.flatMap(x => x.map(_ * 2)

返回结果是

List[Int] = List(2, 4, 6, 8)

  将两个集合折合成一个集合输出,并应用了x*2函数计算。这里_ * 2等同于(x: Int) => x * 2,下划线_表示通配上下文的任何变量或函数。是一种简单写法。

第三步

  让我们还是围绕(x: Int) => x * 2继续展开,它代表一个有输入和输出的函数,如果我们在另外一个函数中需要用这个函数作为输入参数,那么如何定义另外一个函数的方法参数呢?myfunc2(_*2)是一种hard code写法。

def myfunc2(fn: Int => Int): Int = {

  fn(10)

}

  这里的fn: Int => Int匹配(x: Int) => x * 2这样的抽象,当然也可以是(x: Int) => x + 2等,只要输入和输出返回都是整数即可。如果我们运行:

myfunc2((x: Int) => x * 2)

结果是20, 而运行:

myfunc2((x: Int) => x + 2)

结果是12。

  在这里,fn(10)中的10是fn输入参数,fn输出结果是根据myfunc2的输入决定的,有点类似访问者模式哦。

  下面我们尝试写自己的函数组合子:

var myfunc = (x: Int) => x * 2

val numbers = List(1, 2, 3, 4)

def ourMap(numbers: List[Int], fn: Int => Int): List[Int] = {
  numbers.map((x: Int) => x * 2)
}

ourMap(numbers, myfunc(_))

结果是List[Int] = List(2, 4, 6, 8)

时间: 2024-10-01 07:18:20

scala中的map函数与for中的yield的相关文章

python中的map()函数

MapReduce的设计灵感来自于函数式编程,这里不打算提MapReduce,就拿python中的map()函数来学习一下. 文档中的介绍在这里: map(function, iterable, ...) Apply function to every item of iterable and return a list of the results. If additional iterable arguments are passed, function must take that man

python进阶一(函数式编程)【2-2 python中的map函数】

2-2 python中的map()函数 python中map()函数 map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回. 原文地址:https://www.cnblogs.com/ucasljq/p/11609544.html

Python连载43-current中的map函数、xml文件

一.current中的map函数 1.map(fn,*iterable,timeout=None) (1)跟map函数相类似(2)函数需要异步执行(3)timeout代表超时时间 (4)map和submit使用一个就可以 import time,re import os,datetime from concurrent import futures data = ['1','2'] def wait_on(argument): print(argument) time.sleep(2) retu

python3中的 zip()函数 和python2中的 zip()函数 的区别

python3中的 zip()函数 和python2中的 zip()函数 的区别: 描述: zip() 函数用于将可迭代对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象. 如果各个可迭代对象的元素个数不一致,则返回的对象长度与最短的可迭代对象相同. 利用 * 号操作符,与zip相反,进行解压. zip() 函数语法: zip(iterable1,iterable2, ...) 参数说明: iterable -- 一个或多个可迭代对象(字符串.列表.元祖.字典) 返回

Python 中的map函数,filter函数,reduce函数

自学python,很多地方都需要恶补. 三个函数比较类似,都是应用于序列的内置函数.常见的序列包括list.tuple.str. 1.map函数 map函数会根据提供的函数对指定序列做映射. map函数的定义: map(function, sequence[, sequence, ...]) -> list 通过定义可以看到,这个函数的第一个参数是一个函数,剩下的参数是一个或多个序列,返回值是一个集合. function可以理解为是一个一对一或多对一函数,map的作用是以参数序列中的每一个元素调

python中的map函数

1.对可迭代函数'iterable'中的每一个元素应用‘function’方法,将结果作为list返回. 来个例子: >>> def add100(x): ...     return x+100 ... >>> hh = [11,22,33] >>> map(add100,hh) [111, 122, 133] 就像文档中说的:对hh中的元素做了add100,返回了结果的list. 2.如果给出了额外的可迭代参数,则对每个可迭代参数中的元素‘并行’的

C中的qsort函数和C++中的sort函数的理解与使用

一.qsort()函数 原型:_CRTIMP void __cdecl qsort (void*, size_t, size_t,int (*)(const void*, const void*)); 参数解释:1.待排序数组首地址:2.数组中待排序元素数量:3.各元素的占用空间的大小:4.指向函数的指针,用于确定排序的顺序. 说明:qsort函数是ANSI C标准中提供的,其声明在stdlib.h文件中,是根据二分法写的,时间复杂度为O(n*logn). qsort要求提供比较函数用来确定排序

JS中的map()函数

map()方法将调用的数组的每个元素传递给指定的函数,并返回一个数组,它包含该函数的返回值. 传递给map()的函数的调用方式和传递给forEach()的函数的调用方式一样.但传递给map()的函数应该有返回值.注意:map()返回的是新数组:它不修改调用的数组. 举个例子: 要求:为数组 arr 中的每个元素求二次方.不要直接修改数组 arr,结果返回新的数组 实现: function square(arr){ return arr.map(function(item) {  return i

JavaScript中的map()函数

概述Array.map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值,同时不会改变原来的数组. 用法 Array.map(callback); 示例 //简单数组 const arr = [1, 3, 4, 5, 6, 7, 8, 10]; const cube = (num) => { return num * num; } const res = arr.map(cube);//[ 1, 9, 16, 25, 36, 49, 64, 100 ] // or const