Spark 学习3 ——Scala进阶

参见我的掘金

函数式编程 best ref

1.函数定义和高阶函数

函数的类型和值
  • 在非函数式编程语言里,函数的定义包含了**“函数类型”和“值”**两种层面的内容。
  • 在函数式编程中,函数是“头等公民”,可以像任何其他数据类型一样被传递和操作,也就是说,函数的使用方式和其他数据类型的使用方式完全一致
def counter(value: Int): Int = { value += 1}  //  这个函数的“类型” (Int) => Int  当参数只有一个时,括号可以省略
//  只要把函数定义中的类型声明部分去除,剩下的就是函数的“值”
(value) => {value += 1} //只有一条语句时,大括号可以省略
// 上面就是函数的“值”,需要注意的是,采用“=>”而不是“=”,这是Scala的语法要求。
// 我们也可以按照上面类似的形式来定义Scala中的函数:
val counter: Int => Int = { (value) => value += 1 } // 这是函数定义最完整形式,牢记,有各种省略表示法
// counter 是一个函数变量,对比字符串型变量
Lambda表达式
//我们不需要给每个函数命名,这时就可以使用匿名函数,如下:
(num: Int) => num * 2  // 我们经常称为 Lambda表达式
val myNumFunc: Int=>Int = (num: Int) => num * 2
println(myNumFunc(3))  //  传入3,得到乘法结果是6
// Scala具有类型推断机制,可以自动推断变量类型
val myNumFunc = (num: Int) => num * 2  // 常用形式
val myNumFunc= (num) => num * 2 //  error: missing parameter type  全部省略以后,解释器也无法推断出类型
val myNumFunc: Int=>Int = (num) => num * 2
  • 闭包是一个函数,一种比较特殊的函数, 闭包会引用函数外部的变量
val addMore=(x:Int)=>x+more    //  闭包定义的实例
// more并没有在函数中定义,是一个函数外部的变量
高阶函数
  • 函数在Scala中是“头等公民”,它的使用方法和任何其他变量是一样的。一个接受其他函数作为参数或者返回一个函数的函数就是高阶函数。
//定义了一个新的函数sum,以函数f为参数  函数sum是一个接受函数参数的函数,因此,是一个高阶函数。
def sum(f: Int => Int, a: Int, b: Int): Int ={ 
  if(a > b) 0 else f(a) + sum(f, a+1, b)
} // 函数sum的类型是 (Int=>Int, Int, Int) => Int
//定义了一个新的函数self,该函数的输入是一个整数x,然后直接输出x自身
def self(x: Int): Int = x

//定义sumInts函数,调用了函数f 和 函数sum
def sumInts(a: Int, b: Int): Int = sum(self, a, b)
函数和方法的区别
  • Scala中的方法跟Java的方法一样。Scala中的函数是一个完整的对象, Scala中用22个特质(trait)抽象出了函数的概念。ref
  • 方法名是方法调用,而函数名只是代表函数对象本身

2.占位符 “_” 语法

  • 下划线符号“_”在Scala语言中经常会用到,并且出现的场景千变万化。ref

  • 为了让函数字面量更加简洁,我们可以使用下划线作为一个或多个参数的占位符,只要每个参数在函数字面量内仅出现一次。

  1. 匿名函数参数占位符

当匿名函数传递给方法或其他函数时,如果该匿名函数的参数在=>的右侧只出现一次,那么就可以省略=>,并将参数用下划线代替。这对一元函数和二元函数都适用。

val list = List(5,3,7,9,1)
list.map(_ * 10)  //  list.map(x => x * 10)
list.sortWith(_ < _)	// list.sortWith((x, y) => x < y)
list.reduceLeft(_ + _)	// list.reduceLeft((x, y) => x + y)\
// 当匿名函数的参数未被实际使用到时,可以不给它一个命名,而直接用下划线代替
list.foreach(_ => println("Hello Scala")) // 输出 5 个 Hello Scala
  1. 通配符
// 泛型定义中的通配符	在Java中用问号来指代泛型中不确定类型的定义(如List<?>)。Scala用下划线来代替它
def testPrint(l: List[_]) = {
        list.foreach(x => println(x))	}

// 模式匹配中的通配符/占位符
expr match {
  // 以1开头,且长度为3的List
  case List(1,_,_) => "a list with three element and the first element is 1"
  // 长度大于等于0的List
  case List(_*)  => "a list with zero or more elements"
  // 键和值类型都为任意类型的Map
  case Map[_,_] => "matches a map with any key type and any value type"
  case _ =>
}
// 导入语句中的通配符	下划线可以实现Java import语句中星号的作用,但功能更强大一些。利用它还能导入时做重命名,以及忽略某些类。
import java.lang.Math._		// import static java.lang.Math.*
import java.util.{ArrayList => al, _}	// import java.util.*,并将ArrayList重命名为al
import java.util.{Timer => _, _} 	// import java.util.*,但不导入Timer类
  1. 变量默认值初始化
  • 用下划线可以自动在变量声明时,将其赋予默认的初始值
var name : String = _	// name: String = null
var count : Int = _		// count: Int = 0
var avg : Double = _	// avg: Double = 0.0
  1. 访问元组(tuple)
  • 下划线后面跟上数字k,可以当作索引表示元组中的第k个元素。当要忽略元组中的某个值时,也可以用下划线代替它
val tuple = ("LMagics", 173.5, Seq(22,66,88))
tuple._1	// LMagics
  1. 变长参数的转化
  • 下划线与星号连用,可以将序列转化为变长参数的序列,方便调用变长参数的方法。
def sum(args: Int*) = {
     |   var result = 0
     |   for (arg <- args) result += arg
     |   result		}
val sum1 = sum(7,8,9,10,11,12,13,14) // 84
val sum2 = sum(7 to 14: _*)		//	84 // 如果只写7 to 14,会报错
  1. 将方法转换成函数
  • Scala中方法与函数不同,函数在Scala中是一种对象实例,因此它可以赋值给变量,也可以作为参数。如果方法在赋值时直接写名称的话,编译器会认为是对方法的调用,因此会报没有参数列表的错误。
  • 在方法名称后加一个下划线,会将其转化为偏应用函数(partially applied function),就能直接赋值了
def twoSum(a: Int, b: Int) = a + b  // twoSum: (a: Int, b: Int)Int
val twoSumFunc = twoSum _  //  twoSumFunc: (Int, Int) => Int = <function2>

3.针对集合的操作

1.遍历操作
val list = List(1, 2, 3, 4, 5)
for (elem <- list) println(elem)
list.foreach(elem => println(elem)) //本行语句甚至可以简写为list.foreach(println),或者写成:list foreach println
val university = Map( "THU" -> "Tsinghua University","PKU"->"Peking University")
for ((k,v) <- university) printf("Code is : %s and name is: %s\n",k,v)
university foreach {kv => println(kv._1+":"+kv._2)}
2.map操作
  • map操作是针对集合的典型变换操作,它将某个函数应用到集合中的每个元素,并产生一个结果集合

  • flatMap是map的一种扩展。在flatMap中,我们会传入一个函数,该函数对每个输入都会返回一个集合(而不是一个元素),然后,flatMap把生成的多个集合“拍扁”成为一个集合。

val books = List("Hadoop", "Hive", "HDFS")
books.map(s => s.toUpperCase) //  List(HADOOP, HIVE, HDFS)
books flatMap (s => s.toList) // List(H, a, o, o, p, H, i, v, e, H, D, F, S)
books.flatMap(s => s.toList)  // 等价于 books flatMap (s => s.toList)
3.filter操作
  • 遍历一个集合并从中获取满足指定条件的元素组成一个新的集合。Scala中可以通过filter操作来实现
val universityOfXiamen = university.filter{kv => kv._2 contains "Xiamen"}
val universityOfP = university.filter{kv => kv._2 startsWith "P"} // 学校名称中以字母“P”开头的元素
4.reduce操作
  • scala当中的reduce可以对集合当中的元素进行归约操作。reduce包含reduceLeft和reduceRight。reduceLeft就是从左向右归约,reduceRight就是从右向左归约。 参考
val a = Array(12, 6, 15, 2, 20, 9)
a.reduceLeft(_ + _) // 64 是这样的:12+6=18, 18+15=33, 33+2=35, 35+20=55, 55+9=64,就是对集合的所有元素求和
a.reduceLeft(_ * _)    // 所有乘积
a.reduceLeft(_ min _)  // 2  最小值
a.reduceLeft(_ max _)  // 20  最大值
val list = List(1,2,3,4,5)  // reduce默认为reduceLeft 
list.reduce(_ - _)  //  -13
5.fold操作
  • 折叠(fold)操作和reduce(归约)操作比较类似。fold操作需要从一个初始的“种子”值开始,并以该值作为上下文,处理集合中的每个元素。
val list = List(1,2,3,4,5)
list.fold(10)(_*_)   // fold函数实现了对list中所有元素的累乘操作。
// fold函数需要两个参数,一个参数是初始种子值,这里是10,另一个参数是用于计算结果的累计函数,这里是累乘。 首先把初始值拿去和list中的第一个值1做乘法操作
// fold有两个变体:foldLeft()和foldRight() 

WordCount实例

参考

import java.io.File
import scala.io.Source
object WordCount {
    def main(args: Array[String]): Unit = {
        val dirfile = new File("/usr/local/scala/mycode/wordcount")
        val files = dirfile.listFiles
        for (file <-files) println(file)
        val listFiles = files.toList
        val wordsMap = scala.collection.mutable.Map[String,Int]()
        listFiles.foreach( 
            file => Source.fromFile(file).getLines().foreach(
            line=>line.split(" ").foreach(word=>{
            if(wordsMap.contains(word)) {wordsMap(word)+=1} else {wordsMap+=(word->1) } } ) ) )
    } // main
    println(wordsMap)
    for((key,value)<-wordsMap ) println(key+": "+value)
} //object
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值