当前位置: 首页>编程语言>正文

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案


林子雨老师《Spark编程基础》_第二章scala语言_重点

  • 1、scala基础知识
  • 1.1基本数据类型和变量
  • 基本数据类型
  • 字面量(literal)
  • 操作符
  • 富包装类
  • 变量
  • 1.2输入输出
  • 输入
  • 输出
  • 写入文件
  • 读取文件
  • 1.3控制结构
  • 1.3.1if控制
  • 1.3.2while循环
  • 1.3.3for循环
  • 1.3.4异常处理
  • 1.3.5对循环的控制
  • 1.4数据结构
  • 1.4.1数组Array
  • 1.4.2元组Tuple
  • 1.4.3容器Collection
  • 1.4.4序列Sequence
  • 1.4.4.1列表 List
  • 1.4.4.2队列 Queue
  • 1.4.4.3可变数组 ArrayBuffer
  • 1.4.4.4向量 Vector
  • 1.4.5集合Set
  • 1.4.6映射Map
  • 1.4.7迭代器Iterator
  • 2、面向对象编程
  • 2.1类
  • 2.2对象
  • 2.3继承
  • 2.4特质
  • 2.5模式匹配
  • 2.6包
  • 2.7函数式编程
  • 2.7.1.函数定义与使用
  • 2.7.2. 高阶函数
  • 2.7.3针对容器的操作
  • 2.8wordcount
  • 2.8.1wordcount1
  • 2.8.1wordcount2


在解释器中运行scala,一次只运行一行,编写脚本可以运行多行程序。

cd usr/local/scala/mycode

vim test.scala

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_开发语言,第1张

:load /usr/local/scala/mycode/test.scala

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_scala_02,第2张

1、scala基础知识

1.1基本数据类型和变量

基本数据类型

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_List_03,第3张

字面量(literal)

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_scala_04,第4张

操作符

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_List_05,第5张

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_scala_06,第6张

在Scala中,操作符就是方法

例如,5 + 3和(5).+(3)是等价的

富包装类

每个基本类型都有一个对应的富包装类,例如Int有一个RichInt类、String有一个RichString类,这些类位于包scala.runtime中
当对一个基本数据类型的对象调用其富包装类提供的方法,Scala会自动通过隐式转换将该对象转换为对应的富包装类型,然后再调用相应的方法。例如:3 max 5

变量

val:是不可变的,在声明时就必须被初始化,而且初始化以后就不能再赋值
var:是可变的,声明的时候需要进行初始化,初始化以后还可以再次对其赋值
val 变量名:数据类型 = 初始值
var 变量名:数据类型 = 初始值

类型推断机制(type inference):根据初始值自动推断变量的类型,使得定义变量时可以省略具体的数据类型及其前面的冒号

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_Scala_07,第7张

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_scala_08,第8张

1.2输入输出

输入

使用前必须导入scala.io.StdIn

readInt、readDouble、readByte、readShort、readFloat、readLong、readChar readBoolean及readLine,分别对应9种基本数据类型,其中前8种方法没有参数,readLine可以不提供参数,也可以带一个字符串参数的提示

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_Scala_09,第9张

输出

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_scala_10,第10张

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_scala_11,第11张

写入文件

Scala需要使用java.io.PrintWriter实现把数据写入到文件,PrintWriter类提供了print 和println两个写方法

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_后端_12,第12张

读取文件

可以使用scala.io.Source的getLines方法实现对文件中所有行的读取

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_后端_13,第13张

1.3控制结构

1.3.1if控制

if(){
}
else{
}

1.3.2while循环

while(){
}

或

do{

}while(表达式)

1.3.3for循环

生成器 变量<-表达式

for (i<-1 to 3) println(i)

for (i<-Array(1,3,4)) println(i)

守卫式 for (变量 <- 表达式 if 条件表达式)

for (i<-1 to 6 if i%2==0) println(i)

for (i<-1 to 6;j<-1 to 3) println(i*j)
1
2
3
2
4
6
1to3内循环 1to6外循环

for 推导式 for (变量 <- 表达式) yield {语句块}

val r=for (i <- 1 to 6 if i%2==0) yield{println(i);i}

1.3.4异常处理

try 正常执行,没有异常抛出
try执行出错,catch捕捉错误 并与每个 case字句比对
如果都没有匹配到错误,异常将向上层程序体抛出

finally最终执行(可选)

import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException
try{
	val f =new FileReader("input.txt") //文件操作
} catch {
	case ex:FileNotFoundException =>... //文件不存在
	case ex:IOException =>...  //发生I/O错误
} finally {
	file.close()  确保关闭文件
}

1.3.5对循环的控制

Scala没有break和continue关键字
Scala提供了一个Breaks类(位于包scala.util.control)
Breaks类有两个方法用于对循环结构进行控制,即breakable和break

//代码文件为/usr/local/scala/mycode/TestBreak.scala
import util.control.Breaks._ //导入Breaks类的所有方法
val array = Array(1,3,10,5,4)
breakable{
for(i<- array){
	   if(i>5) break //跳出breakable,终止for循环,相当于Java中的break
println(i)
	}
}
// 上面的for语句将输出1,3
 
for(i<- array){
	breakable{
		if(i>5) break 
                            //跳出breakable,终止当次循环,相当于Java的continue		println(i)
	}
}// 上面的for语句将输出1,3,5,4

1.4数据结构

1.4.1数组Array

一种可变的、可索引的、元素具有相同类型的数据集合

val intValueArr = new Array[Int](3)
//长度为3 整型 数组,每个数组元素初始化为0
intValueArr(0) = 12 //给第1个数组元素赋值为12
intValueArr(1) = 45  //给第2个数组元素赋值为45
intValueArr(2) = 33 //给第3个数组元素赋值为33
val myStrArr = new Array[String](3)
//长度为3 字符串 数组,每个数组元素初始化为null

 myStrArr(0) = "BigData"
 myStrArr(1) = "Hadoop"
 myStrArr(2) = "Spark"
 for (i <- 0 to 2) println(myStrArr(i))
可以不给出数组类型,Scala会自动根据提供的初始化数据来推断出数组的类型
val intValueArr = Array(12,45,33)
val myStrArr = Array("BigData","Hadoop","Spark")

多维数组:调用Array的ofDim方法

val  myMatrix = Array.ofDim[Int](3,4)
//类型实际就是Array[Array[Int]]
val  myCube = Array.ofDim[String](3,2,4)
//类型实际是Array[Array[Array[Int]]]
//可以使用多级圆括号来访问多维数组的元素,例如myMatrix(0)(1)返回第一行第二列的元素

1.4.2元组Tuple

如果需要在方法里返回多个不同类型的对象,Scala可以通过返回一个元组来实现
元组是对多个不同类型对象的一种简单封装。定义元组最简单的方法就是把多个元素用逗号分开并用圆括号包围起来。
使用下划线“_”加上从1开始的索引值,来访问元组的元素

val tuple = ("bigdata",2015,45.0)
println(tuple._1)
println(tuple._2)
println(tuple._3)

1.4.3容器Collection

Scala提供了一套丰富的容器(collection)库,包括序列(Sequence)、集合(Set)、映射(Map)等
scala.collection 、scala.collection.mutable和scala.collection.immutable

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_List_14,第14张

1.4.4序列Sequence

元素可以按照特定的顺序访问的容器。序列中每个元素均带有一个从0开始计数的固定索引位置。序列容器的根是collection.Seq特质。
其具有两个子特质 LinearSeq和IndexedSeq
LinearSeq序列具有高效的 head 和 tail 操作
IndexedSeq序列具有高效的随机存储操作
实现了特质LinearSeq的常用序列有列表(List)和队列(Queue)。
Range类:一种特殊的、带索引的不可变数字等差序列。其包含的值为从给定起点按一定步长增长(减小)到指定终点的所有数值
Range可以支持创建不同数据类型的数值序列,包括Int、Long、Float、Double、Char、BigInt和BigDecimal等

val r=new Range(1,5,1)
1 until 5
1 to 10 by 2
0.5f to 5.9f by 0.8f
1.4.4.1列表 List

列表: 一种共享相同类型的不可变的对象序列。
scala的List一旦被定义,其值就不能改变,因此声明List时必须初始化
定义在scala.collection.immutable包中
head返回的是列表第一个元素的值
tail返回的是除第一个元素外的其它值构成的新列表,这体现出列表具有递归的链表结构
除了head、tail操作是常数时间O(1),其它按索引访问的操作都需要从头开始遍历,因此是线性时间复杂度O(N)

var strList=List("BigData","Hadoop","Spark")
//strList.head将返回字符串”BigData”,strList.tail返回List ("Hadoop","Spark")
//构造列表常用的方法是通过在已有列表前端增加元素,使用的操作符为::
val otherList="Apache"::strList
//执行该语句后strList保持不变,而otherList将成为一个新的列表:List("Apache","BigData","Hadoop","Spark")
val intList = 1::2::3::Nil
//与val intList = List(1,2,3)等效
1.4.4.2队列 Queue
// An highlighted block
var foo = 'bar';

实现了特质IndexedSeq的常用序列有可变数组(ArrayBuffer)和向量(Vector)

1.4.4.3可变数组 ArrayBuffer
// An highlighted block
var foo = 'bar';
1.4.4.4向量 Vector

Vetor所有访问操作都是常数时间

val vec1=Vector(1,2)
vec1: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3)
val vec2 = 3 +: 4 +: vec1
vec2: scala.collection.immutable.Vector[Int] = Vector(3, 4, 1, 2)
val vec3 = vec2 :+ 5
vec3:scala.collection.immutable.Vector[Int] = Vector(3, 4, 1, 2, 5)
scala> vec3(3)
res6: Int = 2

1.4.5集合Set

不重复元素的容器(collection)

var mySet = Set("Hadoop","Spark")
mySet += "Scala" 
import scala.collection.mutable.Set
val myMutableSet = Set("Database","BigData")
myMutableSet += "Cloud Computing"

1.4.6映射Map

一系列键值对的容器。键是唯一的,但值不一定是唯一的。可以根据键来对值进行快速的检索

val university = Map("XMU" -> "Xiamen University", "THU" -> "Tsinghua University","PKU"->"Peking University")
println(university("XMU"))
val xmu = if (university.contains("XMU")) university("XMU") else 0 println(xmu)
import scala.collection.mutable.Map
val university2 = Map("XMU" -> "Xiamen University", "THU" -> "Tsinghua University","PKU"->"Peking University")
university2("XMU") = "Ximan University" //更新已有元素的值
university2("FZU") = "Fuzhou University" //添加新元素
university2 + = ("TJU"->"Tianjin University") //添加一个新元素
university2 + = ("SDU"->"Shandong University","WHU"->"Wuhan University") //同时添加两个新元素

1.4.7迭代器Iterator

迭代器(Iterator)不是一个容器,而是提供了按顺序访问容器元素的数据结构
迭代器包含两个基本操作:next和hasNext。next可以返回迭代器的下一个元素,hasNext用于检测是否还有下一个元素
除next和hasnext方法外,在对一个迭代器调用了某个方法后,不要再次使用该迭代器

val iter = Iterator("Hadoop","Spark","Scala")
while (iter.hasNext) {
    println(iter.next())
}

2、面向对象编程

2.1类


方法
构造器

创建类,使用new关键字创建一个类的实例
Scala类中所有成员的默认可见性为公有,任何作用域内都能直接访问公有成员
Scala也提供private和protected,其中,private成员只对本类型和嵌套类型可见;protected成员对本类型和其继承类型都可见
对于private字段,Scala采用类似Java中的getter和setter方法,定义了两个成对的方法value和value_=进行读取和修改
当方法的返回结果类型可以从最后的表达式推断出时,可以省略结果类型

class Count{
    private var privateValue =0
    def value = privateValue
    def value_= (newValue:Int){
      if (newValue>0) privateValue = newValue
    }
    var value_1 = 0
    def increment(step:Int):Unit = { value += step}
    def current():Int = {value}

  }
  
  def main(args: Array[String]): Unit = {
    val mycount = new Count
    mycount.value_1=5
    mycount.increment(5)
    println(mycount.current)
  }

//构造器
  class Counter2 {
    private var value = 0
    private var name = ""
    private var step = 1 //计算器的默认递进步长
    println("the main constructor")
    def this(name: String){ //第一个辅助构造器
      this() //调用主构造器
      this.name = name
      printf("the first auxiliary constructor,name:%s\n",name)
    }
    def this (name: String,step: Int){ //第二个辅助构造器
      this(name) //调用前一个辅助构造器
      this.step = step
      printf("the second auxiliary constructor,name:%s,step:%d\n",name,step)
    }
    def increment(step: Int): Unit = { value += step}
    def current(): Int = {value}
  }

2.2对象

1.单例对象
apply方法
update方法
unapply方法

Scala采用单例对象来实现与Java静态成员同样的功能,使用object 关键字定义单例对象。
当一个单例对象和它的同名一起出现时,这时的单例对象被称为这个同名类的“伴生对象”。相应的类被称为这个单例对象的“伴生类”。类和它的伴生对象必须存在于同一个文件中,可以相互访问私有成员。没有同名类的单例对象,被称为孤立对象。一般情况下,Scala程序的入口点main方法就是定义在一个孤立对象里。

object Person{
    private var lastId = 0  //一个人的身份编号
    def newPersonId() = {
      lastId +=1
      lastId
    }
  }
  class Person(val name:String){
    private val id = Person.newPersonId() //调用了伴生对象中的方法
    def info() {
      printf("The id of %s is %d.\n",name,id)
    }
  }

2.apply方法
apply方法调用约定:用括号传递给类实例或单例对象名一个或多个参数时,Scala 会在相应的类或对象中查找方法名为apply且参数列表与传入的参数一致的方法,并用传入的参数来调用该apply方法

class TestApplyClass {
    def apply(param: String){
      println("apply method called: " + param)
    }
  }

伴生对象中的apply方法:将所有类的构造方法以apply方法的形式定义在伴生对象中,这样伴生对象就像生成类实例的工厂,而这些apply方法也被称为工厂方法
Scala中一切都是对象,包括函数也是对象。Scala中的函数既保留括号调用样式,也可以使用点号调用形式,其对应的方法名即为apply
def add=(x:Int,y:Int)=>x+y
add(4,5)
add.apply(4,5)
Scala的对象也可以看成函数,前提是该对象提供了apply方法

class Car(name: String) {
    def info() {
      println("Car name is "+ name)
    }
  }
  object Car {
    def apply(name: String) = new Car(name) //调用伴生类Car的构造方法
  }
  object MyTestApply{
    def main (args: Array[String]) {
      val mycar = Car("BMW") //调用伴生对象中的apply方法
      mycar.info() //输出结果为“Car name is BMW”
    }
  }

3.update
当对带有括号并包括一到若干参数的对象进行赋值时,编译器将调用对象的update方法,并将括号里的参数和等号右边的值一起作为update方法的输入参数来执行调用

4.unapply方法
unapply方法用于对对象进行解构操作,与apply方法类似,该方法也会被自动调用,可以认为unapply方法是apply方法的反向操作,apply方法接受构造参数变成对象,而unapply方法接受一个对象,从中提取值

class Car(val brand:String,val price:Int) {
    def info() {
        println("Car brand is "+ brand+" and price is "+price)
    }
}
object Car{
	def apply(brand:String,price:Int)= {
                          println("Debug:calling apply ... ")
                          new Car(brand,price)
                  }
	def unapply(c:Car):Option[(String,Int)]={
                           println("Debug:calling unapply ... ")
                           Some((c.brand,c.price))
                 }
}
object TestUnapply{
      def main (args: Array[String]) {
               var Car(carbrand,carprice) = Car("BMW",800000)
               println("brand: "+carbrand+" and carprice: "+carprice)
       }
}

2.3继承

  1. 抽象类:如果一个类包含没有实现的成员,则必须使用abstract关键词进行修饰,定义为抽象类
abstract class Car(val name:String) {
    val carBrand:String //字段没有初始化值,就是一个抽象字段
    def info() //抽象方法
    def greeting() {
        println("Welcome to my car!")
    }
}
  1. 扩展类
    Scala只支持单一继承,而不支持多重继承。在类定义中使用extends关键字表示继承关系。
    重载父类的抽象成员(包括字段和方法)时,override关键字是可选的;而重载父类的非抽象成员时,override关键字是必选的
    只能重载val类型的字段,而不能重载var类型的字段。因为var类型本身就是可变的,所以,可以直接修改它的值,无需重载
abstract class Car1{
    val carBrand:String //字段没有初始化值,就是一个抽象字段
    def info() //抽象方法
    def greeting() {
      println("Welcome to my car!")
    }
  }
  class BYDcar extends Car1{
    override val carBrand = "BYD"
    def info(){print("This is a %s car.",carBrand)}
    override def greeting() {println("Welcome to my BYD car!")}
  }
  1. Scala的类层次结构
  2. spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_Scala_15,第15张

  3. Option类
    Option是一个抽象类,有一个具体的子类Some和一个对象None,其中,前者表示有值的情形,后者表示没有值
    当方法不确定是否有对象返回时,可以让返回值类型为Option[T],其中,T为类型参数。对于这类方法,如果确实有T类型的对象需要返回,会将该对象包装成一个Some对象并返回;如果没有值需要返回,将返回None
  4. spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_Scala_16,第16张

2.4特质

Java中提供了接口,允许一个类实现任意数量的接口
Scala中没有接口的概念,而是提供了“特质(trait)”,它不仅实现了接口的功能,还具备了很多其他的特性
Scala的特质是代码重用的基本单元,可以同时拥有抽象方法和具体方法
Scala中,一个类只能继承自一个超类,却可以实现多个特质,从而重用特质中的方法和字段,实现了多重继承
特质可以使用extends继承其它的特质

trait Flyable {
    var maxFlyHeight:Int  //抽象字段
    def fly() //抽象方法
    def breathe(){ //具体的方法
        println("I can breathe")
    }
  }

把特质混入类中
可以使用extends或with关键字把特质混入类中。如果特质中包含抽象成员,则该类必须为这些抽象成员提供具体实现,除非该类被定义为抽象类

class Bird(flyHeight:Int) extends Flyable{
    var maxFlyHeight:Int = flyHeight  //重载特质的抽象字段
    def fly(){
      printf("I can fly at the height of %d.",maxFlyHeight)
    } //重载特质的抽象方法
  }

如果要混入多个特质,可以连续使用多个with

trait Flyable {
    var maxFlyHeight:Int  //抽象字段
    def fly() //抽象方法
    def breathe(){ //具体的方法
        println("I can breathe")
    }
  }
  trait HasLegs {
    val legs:Int   //抽象字段
    def move(){printf("I can walk with %d legs",legs)}
  }
  class Animal(val category:String){
    def info(){println("This is a "+category)}
  }


  class Bird(flyHeight:Int) extends Animal("Bird") with Flyable with HasLegs{
    var maxFlyHeight:Int = flyHeight //重载特质的抽象字段
    val legs=2 //重载特质的抽象字段
    def fly(){
      printf("I can fly at the height of %d",maxFlyHeight)
    }//重载特质的抽象方法
  }

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_List_17,第17张

2.5模式匹配

match语句
match结构中不需要break语句来跳出判断,Scala从前往后匹配到一个分支后,会自动跳出判断
通配符_相当于Java中的default分支

import scala.io.StdIn._
println("Please input the score:")
val grade=readChar()
grade match{
	case 'A' => println("85-100")
	case 'B' => println("70-84")
	case 'C' => println("60-69")
	case 'D' => println("<60")
	case _ => println("error input!")
}
//case后面的表达式可以是任何类型的常量,而不要求是整数类型
import scala.io.StdIn._
println("Please input a country:")
val country=readLine()
country match{
		case "China" => println("中国")
		case "America" => println("美国")
		case "Japan" => println("日本")
		case _ => println("我不认识!")
}
//除了匹配特定的常量,还能匹配某种类型的所有值
for (elem <- List(6,9,0.618,"Spark","Hadoop",'Hello)){
	val str  = elem match  {
	    case i: Int => i + " is an int value."//匹配整型的值,并赋值给i
	    case d: Double => d + " is a double value." //匹配浮点型的值
	    case "Spark"=>"Spark is found." //匹配特定的字符串
	    case s: String => s + " is a string value." //匹配其它字符串
	    case _ =>"unexpected value:"+ elem  //与以上都不匹配
              }
              println(str)
}

//可以在match表达式的case中使用守卫式(guard)添加一些过滤逻辑
for (elem <- List(1,2,3,4)){
     elem match {
           case _ if (elem%2==0) => println(elem + " is even.")
           case _ => println(elem + " is odd.")
     }
}

case类
当定义一个类时,如果在class关键字前加上case关键字,则该类称为case类
Scala为case类自动重载了许多实用的方法,包括toString、equals和hashcode方法
Scala为每一个case类自动生成一个伴生对象,其包括模板代码
1个apply方法,因此,实例化case类的时候无需使用new关键字
1个unapply方法,该方法包含一个类型为伴生类的参数,返回的结果是Option类型,对应的类型参数是N元组,N是伴生类中主构造器参数的个数。Unapply方法用于对对象进行解构操作,在case类模式匹配中,该方法被自动调用,并将待匹配的对象作为参数传递给它
case class Car(brand: String, price: Int)
object Car{
def apply(brand:String,price:Int)= new Car(brand,price)
def unapply(c:Car):Option[(String,Int)]=Some((c.brand,c.price))
}

case class Car(brand: String, price: Int) 
val myBYDCar = Car("BYD", 89000)
val myBMWCar = Car("BMW", 1200000)
val myBenzCar = Car("Benz", 1500000)
for (car <- List(myBYDCar, myBMWCar, myBenzCar)) {
       car match{
              case Car("BYD", 89000) => println("Hello, BYD!")
              case Car("BMW", 1200000) => println("Hello, BMW!")
              case Car(brand, price) => println(“Brand:”+ brand +“, Price:”+price+“, do you want it?”)   
       }
 }

2.6包

为了解决程序中命名冲突问题,Scala也和Java一样采用包(package)来层次化、模块化地组织程序
通过在关键字package后面加大括号,可以将程序的不同部分放在不同的包里。这样可以实现包的嵌套,相应的作用域也是嵌套的

package xmu {
       package autodepartment {
            class ControlCourse{
		...
           }
      }
     package csdepartment {
           class  OSCourse{
                val cc = new autodepartment.ControlCourse
           }
     }
}

//可以用import 子句来引用包成员,这样可以简化包成员的访问方式
import xmu.autodepartment.ControlCourse
class MyClass{
	var myos=new ControlCourse
}
//使用通配符下划线(_)引入类或对象的所有成员
import scala.io.StdIn._
var i=readInt()
var f=readFloat()
var str=readLine()

2.7函数式编程

2.7.1.函数定义与使用

def counter(value: Int): Int = { value += 1}
(value) => {value += 1} //只有一条语句时,大括号可以省略
val num: Int = 5
val counter: Int => Int = { (value) => value += 1 }

Lambda表达式
(参数) => 表达式
//如果参数只有一个,参数的圆括号可以省略

(num: Int) => num * 2

我们可以直接把匿名函数存放到变量中

val myNumFunc: Int=>Int = (num: Int) => num * 2
println(myNumFunc(3))

当函数的每个参数在函数字面量内仅出现一次,可以省略“=>”并用下划线“_”作为参数的占位符来简化函数字面量的表示,第一个下划线代表第一个参数,第二个下划线代表第二个参数,依此类推

val counter = (_:Int) + 1 //有类型时括号不能省略,等效于“x:Int=>x+1”
val add = (_:Int) + (_:Int) //等效于“(a:Int,b:Int)=>a+b”
val m1=List(1,2,3)
val m2=m1.map(_*2)//map接受一个函数作为参数,相当于“m1.map(x=>x*2)”,参数的类型可以根据m1的元素类型推断出,所以可以省略。

2.7.2. 高阶函数

当一个函数包含其它函数作为其参数或者返回结果为一个函数时,该函数被称为高阶函数

def powerOfTwo(x: Int): Int = {if(x == 0) 1 else 2 * powerOfTwo(x-1)}
def sumInts(a: Int, b: Int): Int = {
		if(a > b) 0 else a + sumInts(a + 1, b)
}
def sumSquares(a: Int, b: Int): Int = {
		if(a > b) 0 else a*a + sumSquares(a + 1, b)
}
def sumPowersOfTwo(a: Int, b: Int): Int = {
		if(a > b) 0 else powerOfTwo(a) + sumPowersOfTwo(a+1, b)
}
def sum(f: Int => Int, a: Int, b: Int):Int = {
	if(a > b) 0 else f(a) + sum(f, a+1, b)
}//直接传入一个匿名函数

scala> sum(x=>x,1,5) //直接传入一个匿名函数
//且省略了参数x的类型,因为可以由sum的参数类型推断出来
res8: Int = 15
scala> sum(x=>x*x,1,5) //直接传入另一个匿名函数
res9: Int = 55
scala> sum(powerOfTwo,1,5) //传入一个已经定义好的方法
res10: Int = 62

2.7.3针对容器的操作

遍历操作
Scala容器的标准遍历方法foreach

val list = List(1, 2, 3)
val f=(i:Int)=>println(i)
list.foreach(f)
list foreach(i=>println(i))
list foreach println
val university = Map("XMU" ->"Xiamen University", "THU" ->"Tsinghua University","PKU"->"Peking University")
university foreach{kv => println(kv._1+":"+kv._2)}
university foreach{x=>x match {case (k,v) => println(k+":"+v)}}
university foreach{case (k,v) => println(k+":"+v)}
// An highlighted block
var foo = 'bar';

映射操作
映射是指通过对容器中的元素进行某些运算来生成一个新的容器。两个典型的映射操作是map方法和flatMap方法
map方法(一对一映射):将某个函数应用到集合中的每个元素,映射得到一个新的元素,map方法会返回一个与原容器类型大小都相同的新容器,只不过元素的类型可能不同

val books =List("Hadoop","Hive","HDFS")
books.map(s => s.toUpperCase)//toUpperCase方法将一个字符串中的每个字母都变成大写字母
books.map(s => s.length) //将字符串映射到它的长度

flatMap方法(一对多映射):将某个函数应用到容器中的元素时,对每个元素都会返回一个容器(而不是一个元素),然后,flatMap把生成的多个容器“拍扁”成为一个容器并返回。返回的容器与原容器类型相同,但大小可能不同,其中元素的类型也可能不同

scala> books flatMap (s => s.toList)
res58: List[Char] = List(H, a, d, o, o, p, H, i, v, e, H, D, F, S)

过滤操作
筛选所输入的元素,将其整理为一个容器返回

val university = Map("XMU" ->"Xiamen University", "THU" ->"Tsinghua University","PKU"->"Peking University","XMUT"->"Xiamen University of Technology")
val xmus = university filter {kv => kv._2 contains "Xiamen"}

Map(XMU -> Xiamen University, XMUT -> Xiamen University of Technology)

val l=List(1,2,3,4,5,6) filter {_%2==0}

List[Int] = List(2, 4, 6)

规约操作

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_后端_18,第18张

val list = List(1,2,3,4,5)
list reduceLeft {_-_} // -13
list reduceRight {_-_} // 1-(2-(3-(4-5)))=3

val s = list map (_.toString)  //将整型列表转换成字符串列表
s reduceLeft {(accu,x)=>s"($accu-$x)"}
s reduceRight {(x,accu)=>s"($x-$accu)"}

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_scala_19,第19张

fold方法:一个双参数列表的函数,从提供的初始值开始规约。第一个参数列表接受一个规约的初始值,第二个参数列表接受与reduce中一样的二元函数参数

spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案,spark编程编程基础 林子雨 课后答案解析 spark编程基础林子雨版答案_Scala_20,第20张

val list =List(1,2,3,4,5)
list.fold(10)(_*_) //1200
(list fold 10)(_*_) //fold的中缀调用写法
(list foldLeft 10)(_-_)//计算顺序(((((10-1)-2)-3)-4)-5)
(list foldRight 10)(_-_) //计算顺序(1-(2-(3-(4-(5-10)))))

2.8wordcount

2.8.1wordcount1

package org.example
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object wc61_gpb {

  def main(args: Array[String]): Unit = {
    //新建sparkconf对象
    // 在本地运行
    val conf = new SparkConf().setMaster("local[*]").setAppName("sparkcore_worldcount")
    //打jar包上集群运行
    //val conf = new SparkConf().setAppName("sparkcore_worldcount")
    //创建sparkcontext
    val sc = new SparkContext(conf)
    //读取数据
    val textfile = sc.textFile(args(0))
    //val textfile = sc.textFile("D:\1Adssj\spark\wc6_gpb\input\test_wc.txt")
    //val textfile = sc.makeRDD(List("gao","peng","bo","yang","li","gao"))
    //按照空格进行切分
    val worlds = textfile.flatMap(_.split(" "))
    //转换为k v 结构
    val k2v = worlds.map((_,1))
    //将形同的key进行合并
    val result = k2v.reduceByKey(_+_)
    //输出结果
    result.saveAsTextFile(args(1))
    //关闭连接
    //result.saveAsTextFile(args(1))
    sc.stop()
  }

}

2.8.1wordcount2

package org.example
import java.io.File
import scala.io.Source
import collection.mutable.Map
object wc1 {
  def main(args: Array[String]): Unit = {
    val dirfile=new File("testfiles")
    val files  = dirfile.listFiles
    val results = Map.empty[String,Int]
    for(file <-files) {
      val data= Source.fromFile(file)
      val strs =data.getLines.flatMap{s =>s.split(" ")}
      strs foreach {word =>
        if (results.contains(word))
          results(word)+=1 else  results(word)=1
      }
    }
    results foreach{case (k,v) => println(s"$k:$v")}
    }
}



https://www.xamrdz.com/lan/52v1962648.html

相关文章: