14.1 偏函数
14.1.1 一个简单的需求
给你一个集合
val list = List(1, 2, 3, 4, "abc")
,请完成如下要求: 将集合
list
中的所有数字+1
,并返回一个新的集合 要求忽略掉非数字的元素,即返回的新的集合形式为(2, 3, 4, 5)
思路1: 使用filter
+ map
package com.atguigu.day12
object PianHanDemo1 {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3, 4, "abc")
val list2: List[Int] = list.filter(f1).map(f2).map(f3)
println(list2)
}
def f1(n: Any): Boolean = {
n.isInstanceOf[Int]
}
def f2(n: Any): Int = {
n.asInstanceOf[Int]
}
def f3(n: Int) = {
n + 1
}
}
思路2: 模式匹配
package com.atguigu.day12
object PianHanDemo2 {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3, 4, "abc")
println(list.map(addOne))
}
def addOne(i: Any): Any = {
i match {
case x: Int => x + 1
case _ =>
}
}
}
这种解决方法有问题!
14.1.2 偏函数基本概念
被大括号包含起来的一组case
语句就是一个偏函数.
偏函数并非对所有的输入值都有定义.
偏函数是PartialFunction[A,B]
特质的一个实例.(A
是参数类型, B
是返回值类型)
1. 创建偏函数
package com.atguigu.day12
object ParDemo3 {
def main(args: Array[String]): Unit = {
val f1 = new PartialFunction[Any, Int] {
// 接受传入的参数, 如果返回值值是true, 则会调用apply来创建对象
override def isDefinedAt(x: Any): Boolean = x.isInstanceOf[Int]
//
override def apply(v1: Any): Int = v1.asInstanceOf[Int] + 1
}
val list = List(1, 2, 3, 4, "abc")
val list2: List[Int] = list.collect(f1)
println(list2)
}
}
说明:
创建偏函数需要重写两个方法:
isDefinedAt
和apply
接受传入的参数, 如果返回值值是
true
, 则会调用apply
来创建对象, 如果false
, 则不会调用apply
方法, 相当于忽略了该元素.构建偏函数时,参数形式
[Any, Int]
是泛型,第一个表示参数类型,第二个表示返回参数当使用偏函数时,会遍历集合的所有元素,编译器执行流程时先执行
isDefinedAt()
如果为true
,就会执行apply
, 构建一个新的Int
对象返回 执行isDefinedAt()
为false
就过滤掉这个元素,即不构建新的Int
对象.map
函数不支持偏函数,因为map
底层的机制就是所有循环遍历,无法过滤处理原来集合的元素collect
函数支持偏函数. 可以看成是filter + map
2. 创建偏函数的简写方式
package com.atguigu.day12
object ParDemo4 {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3, 4, "abc")
// 简写方式1: 花括号内直接写case语句, 就是一个偏函数
val f1: PartialFunction[Any, Int] = {
case x: Int => x + 1
}
println(list.collect(f1))
// 简写方式2:
val list2: List[Int] = list.collect({ case x: Int => x + 1 })
println(list2)
}
}