值函数
def add(x : Int, y: Int) =x+y
val _add = add _
val valFunName = funName _
嵌套函数
def里套def,功能上类似于java中的private方法。
def add3(x : Int , y : Int , z : Int) : Int = {
def add2(x : Int , y : Int ) : Int = {
x+y
}
add2(add2(x,y),z)
}
内层函数可以访问外层函数里的变量。
匿名函数
- (参数名:参数类型) => 表达式
- 可将匿名函数赋值给var或val。
val fun = (x:Int) =>x+2
fun(10)
val l = List(1,2,3,4)
l.map((x:Int) => x*2)
l.map(2 * _ )//如果map只有一个参数,scala可以用一个下划线来代替这个参数
def a = (x:Int) => 2*x
var b = (x:Int) => 2*x
l.map(a)
l.map(b)
(x:Int,y:Int) => x+y
函数作为参数
scala中允许函数作为参数传给其它函数,在java中,只能通过给函数传递类对象,然后调用该类的方法来实现这种功能,而在c++中,则是用函数指针来完成的。 一个接收函数作为参数的函数,称为高阶函数。
- fun(函数参数)
def fun(f:(Int,Int) => Int) :Int = f(1,2)
fun((x:Int,y:Int) => x+y) //3
fun((x:Int,y:Int) => x-y) //-1
fun((x:Int,y:Int) => x/y) //0
def mulBy(factor : Double) = (x:Double) => factor * x
//后面的函数的参数来源于前面的函数的参数。
val aa = mulBy(2)
aa(20) //40
闭包
闭包=代码+用到的非局部变量.
参数简化与类型推导
- list.map((x:Int) => x+1)
- list.map((x) => x+1)
- list.map(x =>x+1)
- list.map(_ + 1)
partial function
有的时候调用一个函数,我们只能拿到部分参数的值,而另外的参数暂时不能确定。
def add(x:Int,y:Int,z:Int) = x+y+z
val a = add(1,2,3)
val b = add(1,2,_ :Int)//此时b是一个偏函数了
b(10)//13
def _add = add(_:Int,_:Int,0)//此时_add也是一个偏函数
_add(1,2)//3
Currying
即把参数分开来写,此时可以用于偏函数。
def add(x:Int)(y:Int) = x+y
add(1)_//此时是一个偏函数
重要的高阶函数
- map
- filter
- reduce/reduceLeft/reduceRight
- fold/foldLeft/foldRight
val a = Array(1,2,3,4,5,6,7,8)
a.map(2*_)
a.filter(_ > 4)
a.reduce((x:Int,y:Int) => x+y)
a.reduce(_ + _)//36
a.fold(0)(_+_)//类似于reduce,但是可以提供一个初始值
By-name parameter
by value vs by name。如果是传值则在调用函数的时候就会求出参数表达式的值。如果是传名字,只有在用到的时候才会求值,延迟加载。
def test(flag: Boolean){
println(flag)
}
//by value调用的时候就立刻求值
def test(flag :=> Boolean){
println(flag)
}
//by name延迟计算,用到的时候才会求值
test(3>1)
def fun(block : => Unit){
block
}
fun(println("xxx"))
fun{println("xxxx")}
下面我们来讲scala的集合。注意,scala的集合操作与spark的操作是平行的。
Seq
- Range(start : Int, end : Int, step : Int).
- Range方法带有apply()。
- step可为正或者负,但不能为0.
1 to 10 //包含10
1.until(10) //不包含10
Range(1,10,3)//左闭右开
Range(100,10,-1)
List
List()产生的是一个不可变list。 - List 由Nil或者head + tail构成。其中tail又是一个List,Nil会生成一个空的list。 - 可以用双冒号来在list的头插入新元素。格式是new-value :: list - 构建: List(1,2,3) 或者 1 :: 2 :: 3 :: Nil - 基于List的模式匹配 - 利用迭代或者递归来处理List
val a = Nil //a为List()
val l = List(1,2,3,4)
l.head //1
l.tail //(2,3,4)
可变集合与不可变集合
不可变集合从来不改变,因此你可以安全的共享其引用。你所有的操作都会生成一个新的集合,而不影响原集合,相反,对于可变集合来说,你的一些操作会影响到被操作的集合。scala会优先采用不可变集合。虽然我们可以同时往可变集合和不可变集合中添加元素,但是发生的事情是不一样的,对于不可变集合来讲,是新产生了一个集合,而可变集合则不同,还是原来的集合。
- scala.collection.mutable.Map
- scala.collection.immutable.Map
- scala.collection.mutable.List
- scala.collection.immutables.List
如果我们想定义可变集合,可以通过下面的语句来简写可变的集合:
scala.collection.mutable.Map(1 -> 2)
//或者,更简单的方式是:
import scala.collection.mutable
mutable.Map(1->2)
ListBuffer生成可变列表
可以进行的操作有+=/++=/-=/--=,进行操作之后返回的是自己,而不是产生一个新的集合。可以用toList或者toArray来讲可变列表变成不可变集合。
val b = mutable.ListBuffer(1)
b +=2 //ListBuffer(1,2)
b +=(3,4,5) //ListBuffer(1,2,3,4,5)
b ++= List(6,7,8) //ListBuffer(1,2,3,4,5,6,7,8)
val a = b.toList //a是一个不可变列表了
immutable Set
注意所有的immutable集合是不能有+=这种操作符的,而只能是下面的操作符:
- +/++
- -/--
- scala.collection.immutable.SortedSet,如果你想用排序集合,可以用SortedSet, scala会用TreeSet来帮你排序.
val s = Set(1,2,3) //s是一个不可变set
val a = s+5 //a也是一个不可变set,是由s生成的新set
val b = s+(4,5,6)
val c = s++List(7,8,9)
scala.collection.immutable.SortedSet(2,1,3,4)//TreeSet(1,2,3,4)
mutable Set
- +/++/-/--都会创造一个新的set,原set不变。
- +=/++=/-=/--=则不会创造一个新的set,直接对原set进行修改。
- scala.colletion.mutable.SortedSet(trait)
- TreeSet & BitSet
集合的重要方法
- map
- foreach/take
- filter
- flatten/flatMap
- reduce/fold reduceLeft/foldLeft or Right
- sum/max/min/count
- zip
val l = List(1,2,3,4,5,6,7,8)
l.map(_ * 2).filter(_ > 8).foreach(println(_))
l.take(4) //List(1,2,3,4)拿出前4个元素
l.map(_ * 2).filter(_ > 8).reduce(_ + _)
l.map(_ * 2).filter(_ > 8).fold(0)(_ + _)
l.max
l.sum
l.count(_ > 4)
val l1 = List(1,2,3)
val l2 = List("a","b","c","d")
l1 zip l2 //List((1,a),(2,b),(3,c))
val list = List(List(1,2),List(3,4),List(5,6))
list.flatten //List(1,2,3,4,5,6)
list.flatMap(_.map(2*_))//
list.map(_.map(2*_))//List(List(2,4),List(6,8),List(10,12))
List(1,2,3,4).reduce( - )的运行过程是((1-2)-3)-4,即,对第一个元素和第二个元素调用操作函数,将结果与第三个元素再进行操作函数调用,依次进行。如果是reduceRight(_ + _),则会遵循下面的计算过程:1-(2-(3-4)),也就是说,将最后两个元素做操作,然后将结果作为第二操作数与倒数第三个元素一起进行下一次操作,以此类推。
fold()是和reduce()类似的函数,只不过它提供了初始值,表示从这个初始值作为第一个参数开始进行计算。
关于zip函数,如果l1和l2元素个数不相同时,只会短列表的元素个数,长列表多余的元素会被忽略掉。
flatten函数可以将列表里面包含的列表打开来。 flatMap则是将list的list操作之后将内层list打开。
Comments !