• 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相关推荐

  1. each,collect map collect! map!

    arr = [1,2,3] 1) arr2 = arr.each{|element| element = element * 2} #arr与arr2仍然都等于[1,2,3]   each返回原数组 ...

  2. Scala中的Map使用例子

    Map结构是一种非常常见的结构,在各种程序语言都有对应的api,由于Spark的底层语言是Scala,所以有必要来了解下Scala中的Map使用方法. (1)不可变Map 特点: api不太丰富 如果 ...

  3. scala学习笔记-Map与Tuple(10)

    创建Map 1 // 创建一个不可变的Map2 val ages = Map("Leo" -> 30, "Jen" -> 25, "Jac ...

  4. java8 stream().map().collect()用法

    java8 stream().map().collect()用法 有一个集合: List<User> users = getList(); //从数据库查询的用户集合 现在想获取User的 ...

  5. Scala—— 18.映射Map

    Scala中的Map和Java类似,也是一个散列表,它存储的内容也是键值对(key-value)映射,Scala中不可变的Map是有序的,可变的Map是无序的. Scala中,有可变Map(scala ...

  6. Scala映射(Map)

    Scala映射是键/值对的集合.任何值都可以根据其键来检索.键在映射中是唯一的,但值不是唯一的. 映射有两种:不变的和可变的.默认情况下,Scala使用不可变映射. 如果想要使用可变映射,就必须导入 ...

  7. Stream的特性、用法、stream().map().collect()用法

    Stream的特性.用法.stream().map().collect()用法 1.举例说明 有一个集合: List<User> users = getList(); 现在想获取User的 ...

  8. java8 .stream().map().collect() 的用法

    API: https://www.runoob.com/java/java8-streams.html mylist.stream().map(myfunction->{return item; ...

  9. Scala偏函数使用示例

    引言 传统解决思路 package com.zxl.scalaobject PartiakFunDemo1 {def main(args: Array[String]): Unit = {val li ...

最新文章

  1. Java高级-线程同步机制实现
  2. CISCO NAT 经典配置合集
  3. Word提供的【样式和格式】设计!
  4. PAT甲级1017 Queueing at Bank:[C++题解]字符串、结构体、最小堆
  5. html一个div浮动在另一div上,css – 在另一个DIV的顶部浮动DIV
  6. Java笔记(基础第二篇)
  7. 徒手实现Spring的IOC
  8. 用android制作一个记事本app_用扁平化呈现一个天气APP
  9. 百度鹰眼Web服务API开发使用教程
  10. MySql Binlog初识
  11. 【USACO 2.4】Fractions to Decimals(分数转小数)
  12. 关于多表的leftJoin(转)
  13. 产品画的Axure原型图打不开解决办法
  14. 马赛克(蒙太奇)图片生成--Python实现
  15. excel中使用VBA如何统计数据区域最后一行行号?
  16. 怎么用计算机解锁,一加6T解锁BL教程,利用电脑进行一键解锁Bootloader操作
  17. 使用IDAPython dump 内存
  18. 模版之AnyType
  19. XenDesktop中如何重定向USB设备
  20. java-php-python-ssm外贸服装订单管理系统计算机毕业设计

热门文章

  1. python rsa加密解密 字符串_python_rsa加密解密
  2. 【java学习之路】(javaWeb篇)002.CSS
  3. Spring main方法中怎么调用Dao层和Service层的方法
  4. php提示修改成功,提示修改成功后怎么换回原来的页面
  5. 极光推送 java 绑定别名_Android 极光推送设置别名
  6. 关闭进程_当手机快没电时,别再结束进程关闭手机了,不仅没用还更耗电
  7. VS2010+Opencv_2.4.7+win7的配置攻略及错误解决
  8. 一篇文章教你如何使用makerfile
  9. SURF 与 SIFT的共同点与区别
  10. CSS设置文本——行间距