scala 偏函数与 map/collect
- https://fangjian0423.github.io/2015/06/14/scala-partial/
- https://www.jianshu.com/p/fa2ed7ed391e
0. collect 与 map 的区别
由于collect方法接收的是一个偏函数类型,所以它并不能接收一个lambda表达式:
scala> List(1, 3, 5, "seven").collect(i => i + 1) error: type mismatch;scala> List(1, 3, 5, "seven").collect{case i => i + 1} error: type mismatch;scala> List(1, 3, 5, "seven").collect{case i:Int => i + 1} List[Int] = List(2, 4, 6)
我们在使用collect时,可以利用偏函数的原理,同时实现filter与map的特性。例如:
List(1, 2, 3, 4, 5, 6) collect { case i if i % 2 == 0 => i * i } // 等价于 List(1, 2, 3, 4, 5, 6).filter(i => i % 2 == 0).map(i => i * i)
1. 普通函数与偏函数
普通函数的定义中,有指定的输入类型,所以可以接受任意该类型下的值。比如一个(Int) => String的函数可以接收任意Int值,并返回一个字符串。
偏函数的定义中,也有指定的输入类型,但是偏函数不接受所有该类型下的值。比诶如(Int) => String的偏函数不能接收所有Int值为输入(通过 case 进行指定)。
def one:PartialFunction[Int, String] = {case 1 => "one" }one(1) // "one" one(2) // 报错def two: PartialFunction[Int, String] = {case 2 => "two" }two(1) // 报错 two(2) // "two"def wildcard: PartialFunction[Int, String] = {case _ => "something else" }wildcard(1) // "something else" wildcard(2) // "something else"
由于偏函数只会接收部分参数,所以可以使用 “orElse” 方法进行组合:
val partial = one orElse two orElse wildcardpartial(1) // "one" partial(2) // "two" partial(3) // "something else"
2. 偏函数常见成员
orElse
isDefinedAt:判断偏函数是否对参数中的参数有效
one.isDefinedAt(1) // true one.isDefinedAt(2) // false
case语句其实是偏函数定义的语法糖,当我们编写一个case语句时,其实等同于创建了一个具有apply与isDefineAt方法的偏函数对象。
当我们使用PartialFunction类型定义一个偏函数的时候,scala会被自动转换:
def int2Char: PartialFunction[Int, Char] = {case 1 => 'a'case 3 => 'c' }
会被转化为:
val int2Char = new PartialFunction[Int, Char] {def apply(i: Int) = {case 1 => 'a'case 3 => 'c'}def isDefinedAt(i: Int): Boolean = i match {case 1 => truecase 3 => truecase _ => false} }
3. map/collect 的区别
map 与 collect 等价的情况:
val languageToCount = Map("Scala" -> 10, "Java" -> 20, "Ruby" -> 5) languageToCount map { case (_, count) => count + 1 }languageToCount collect { case (_, count) => count + 1 }
collect 运行正常,map 运行失败:
List(1, 3, 5, "seven") map { case i: Int => i + 1 } //won't work //scala.MatchError: seven (of class java.lang.String) List(1, 3, 5, "seven") collect { case i: Int => i + 1 } //it works
map 与 collect 的 api:
def map[B](f: (A) ⇒ B): List[B]def collect[B](pf: PartialFunction[A, B]): List[B]
两个方法的定义如出一辙,区别就在于前者接收的是一个函数类型的参数,而后者接收的是一个偏函数(partial function)类型的参数:
map: Builds a new collection by applying a function to all elements of this list.
colect: Builds a new collection by applying a partial function to all elements of this list on which the function is defined.
我们可以对比map方法和collect方法的实现:
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {def builder = {val b = bf(repr)b.sizeHint(this)b}val b = builder for (x <- this) b += f(x) b.result }def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {val b = bf(repr)for (x <- this) if (pf.isDefinedAt(x)) b += pf(x) b.result }
在调用map方法时,一旦遍历到值"seven",并调用f(x),因为类型不符合模式匹配中的Int类型,导致抛出MatchError错误。而collect方法在调用pf(x)之前,调用了pf的isDefinedAt(x)作了一次过滤。
scala 偏函数与 map/collect相关推荐
- each,collect map collect! map!
arr = [1,2,3] 1) arr2 = arr.each{|element| element = element * 2} #arr与arr2仍然都等于[1,2,3] each返回原数组 ...
- Scala中的Map使用例子
Map结构是一种非常常见的结构,在各种程序语言都有对应的api,由于Spark的底层语言是Scala,所以有必要来了解下Scala中的Map使用方法. (1)不可变Map 特点: api不太丰富 如果 ...
- scala学习笔记-Map与Tuple(10)
创建Map 1 // 创建一个不可变的Map2 val ages = Map("Leo" -> 30, "Jen" -> 25, "Jac ...
- java8 stream().map().collect()用法
java8 stream().map().collect()用法 有一个集合: List<User> users = getList(); //从数据库查询的用户集合 现在想获取User的 ...
- Scala—— 18.映射Map
Scala中的Map和Java类似,也是一个散列表,它存储的内容也是键值对(key-value)映射,Scala中不可变的Map是有序的,可变的Map是无序的. Scala中,有可变Map(scala ...
- Scala映射(Map)
Scala映射是键/值对的集合.任何值都可以根据其键来检索.键在映射中是唯一的,但值不是唯一的. 映射有两种:不变的和可变的.默认情况下,Scala使用不可变映射. 如果想要使用可变映射,就必须导入 ...
- Stream的特性、用法、stream().map().collect()用法
Stream的特性.用法.stream().map().collect()用法 1.举例说明 有一个集合: List<User> users = getList(); 现在想获取User的 ...
- java8 .stream().map().collect() 的用法
API: https://www.runoob.com/java/java8-streams.html mylist.stream().map(myfunction->{return item; ...
- Scala偏函数使用示例
引言 传统解决思路 package com.zxl.scalaobject PartiakFunDemo1 {def main(args: Array[String]): Unit = {val li ...
最新文章
- Java高级-线程同步机制实现
- CISCO NAT 经典配置合集
- Word提供的【样式和格式】设计!
- PAT甲级1017 Queueing at Bank:[C++题解]字符串、结构体、最小堆
- html一个div浮动在另一div上,css – 在另一个DIV的顶部浮动DIV
- Java笔记(基础第二篇)
- 徒手实现Spring的IOC
- 用android制作一个记事本app_用扁平化呈现一个天气APP
- 百度鹰眼Web服务API开发使用教程
- MySql Binlog初识
- 【USACO 2.4】Fractions to Decimals(分数转小数)
- 关于多表的leftJoin(转)
- 产品画的Axure原型图打不开解决办法
- 马赛克(蒙太奇)图片生成--Python实现
- excel中使用VBA如何统计数据区域最后一行行号?
- 怎么用计算机解锁,一加6T解锁BL教程,利用电脑进行一键解锁Bootloader操作
- 使用IDAPython dump 内存
- 模版之AnyType
- XenDesktop中如何重定向USB设备
- java-php-python-ssm外贸服装订单管理系统计算机毕业设计
热门文章
- python rsa加密解密 字符串_python_rsa加密解密
- 【java学习之路】(javaWeb篇)002.CSS
- Spring main方法中怎么调用Dao层和Service层的方法
- php提示修改成功,提示修改成功后怎么换回原来的页面
- 极光推送 java 绑定别名_Android 极光推送设置别名
- 关闭进程_当手机快没电时,别再结束进程关闭手机了,不仅没用还更耗电
- VS2010+Opencv_2.4.7+win7的配置攻略及错误解决
- 一篇文章教你如何使用makerfile
- SURF 与 SIFT的共同点与区别
- CSS设置文本——行间距