大数据学习笔记3-Scala

Sabthever

Hadoop3

九.Scala

(一)前期

  • 数据分析专用语言
  • 源自Java
    • 构建在JVM上
    • 与Java兼容、互通
  • 优势
    • 多范式编程:面向对象、函数式
    • 表达能力强,代码精简
  • 大数据Scala
    • Spark采用Scala语言设计
    • 提供的API更加优雅
    • 基于JVM的语言更融入Hadoop生态圈

(二)内容介绍

  • 一般要idea和终端配合使用
  • image-20240723110635874

(三)开发环境搭建

  • 2.11.8版本配合后面Spark
  1. 语言安装

    对于scala-2.11.8.msi,一路往后next就行了

  2. 进入cmd

    scala看是否能用

  3. idea中安装插件

    • 联机安装,在前面的界面中Plugins找Scala插件install

    • 离线安装,自己找方法去,找到zip和jar后(要对应好idea的相应版本),Settings->Plugins->Install plugin from disk

      https://plugins.jetbrains.com/plugin/1347-scala

(四)基础语法

1.初次使用

A.建立idea scala工程

  1. 仍然使用Maven-quickstart,因为Scala的选项全用国外源
  2. 三处版本改好
  3. 在main中右键新建一个scala目录
  4. 右击scala目录,Mark Directory As->Resources Root
  5. alt ctrl shift s ->Libraries->+号->加入scala-sdk->ok->ok

B.第一个Scala对象

  1. 右击scala包,scala class->com.njupt.firstscala.First要选Object

  2. main回车会直接跳出来,写下hello world

    1
    2
    3
    4
    5
    6
    7
    package com.njupt.firstscala

    object First {
    def main(args: Array[String]): Unit = {
    println("Hello,world!!!")
    }
    }

    Unit那是返回值,相当于void,=是固定语法

  3. 调用Java中的函数

    image-20240723103410534

    • scala调用Java
    1
    2
    3
    4
    5
    6
    public class App1
    {
    public void kkk(String name) {
    System.out.println(name+"你好");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    object First {
    def main(args: Array[String]): Unit = {
    val app = new App1();
    app.kkk("张三丰");
    println("Hello,world!!!");
    }
    }
    • Java调用Scala

      1
      2
      3
      4
      5
      object First {
      def xxx(name:String):String={
      return name+",你坏!!";
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      public class App1
      {
      public static void main( String[] args )
      {

      System.out.println( "Hello World!" + First.xxx("张无忌") );
      }
      }

      First是一个对象,不用创建直接调用

c.流式语法初试

  • 对于数组每一个加2,过滤出偶数,然后逐行输出

    1
    2
    3
    4
    def main(args: Array[String]): Unit = {
    val arr=Array(1,22,13,56,78,77);
    arr.map(x=>x+2).filter(x=>x%2==0).foreach(println);
    }

2.关键字表

image-20240723113048949

3.变量与常量

image-20240723112629251
  • 例子 变量

    1
    2
    var a:Int=10;
    var a=10; // 也行
  • 例子 常量

    1
    2
    val b:Int=20;
    val b=20; // 也行
  • 内部有类型识别器会自动识别

4.数据类型

A.包装类型
  • Scala认为一切皆对象,因此首字母全都是大写,比Java还纯粹,Java中是基本类型,Scala是包装类型。
  • 变量底下有很多很多方法,连基本运算都是方法。

image-20240723113440788

B.数据类型层次结构
  • image-20240723114006302

5.字符串插值器

  • s型插值器

    image-20240723114610274

    1
    2
    3
    4
    var name="张三";
    var name2="李四";
    println(s"${name}${name2}是朋友")
    // 结果:张三和李四是朋友

6.判断语句

A.if语句
  • 和Java一样直接用

  • 并且支持如下语法,Scala中不支持三元表达式

    1
    2
    3
    var num=20;
    var res = if(num%2==0) 1 else 2;
    println(res);
B.while
  • 和Java一样用,do...while也没有区别
C.for循环
  • image-20240723115123313

    to是1<=i<=num

    until是1<=i<num

    by后面跟着的是步长

    1
    2
    3
    4
    // 这是10-5输出 步长为-1
    for(g:Int <- 10 to 5 by -1) {
    println(g);
    }
  • <-这个是个组合符号

  • foreach用法

    1
    2
    3
    4
    val arr=Array(1,22,13,56,78,77);
    for(i:Int <- arr) {
    println(i)
    }
  • for循环过滤

    1
    2
    3
    4
    for(i:Int <- 1 to 10 ; if i%2==0) {
    print(i);
    }
    // 输出246810

    后面可以跟着多条件,这些条件相当于是&&的关系

    1
    for(i:Int <- 1 to 10 ; if 条件1; if 条件2……){}
D.中断
  • break

    要导入包才可以用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import scala.util.control.Breaks.break
    for(i:Int <- arr) {
    if(i%2!=0) break;
    print(i+" ")
    }
    //或者break()也行,但是不管怎么样都会抛出错误,因此应该
    import scala.util.control.Breaks.{break, breakable}
    breakable{
    for(i:Int <- arr) {
    if(i%2!=0) break;
    print(i+" ")
    }
    }

    breakable相当于规定了跳转的位置

    因此可以如下替代continue的用法,scala中没有continue

    1
    2
    3
    4
    5
    6
    for(i:Int <- arr) {
    breakable{
    if(i%2!=0) break();
    print(i+" ")
    }
    }
E.match

相当于Java 的switch,但是功能有增强。_相当于其他

1
2
3
4
5
6
7
8
9
10
11
12
scala> arr.groupBy(x=>{
| x match {
| case i if i%2==0 => "even"
| case _ => "odd"
| }
| })
res2: scala.collection.immutable.Map[String,Array[Int]] = Map(odd -> Array(1, 3435, 89), even -> Array(22, 56, 8))
scala> arr.groupBy(x=>x match{
| case i if i%2==0 => "even"
| case _ => "odd"
| })
res3: scala.collection.immutable.Map[String,Array[Int]] = Map(odd -> Array(1, 3435, 89), even -> Array(22, 56, 8))
  • 模式匹配

    image-20240726111454623

    • 模式后面加if是模式守卫
  • 可用于类型判定

    image-20240726111548345
  • 可用于样例类内部值直接判定

    image-20240726111636916
    • 例1 找到了sid为”zs”的,并且提取了他的birthday,gender值
    1
    2
    3
    4
    5
    6
    val zs = Student("1", "zs", "1999-10-12", "男")
    zs match{
    case Student(sid,"zs",birthday,gender)=>println(s"看到张三了${birthday}")
    case _=>println("没有找到")
    }
    // 看到张三了1999-10-12
    • 例2 模式守卫
    1
    2
    3
    4
    zs match{
    case Student(sid,"zs",birthday,gender) if birthday.toInt>=10 =>println(s"看到张三了${birthday}")
    case _=>println("没有找到")
    }
    • 例3 由这个知道,样例类自带unapply,但是普通类没有,需要自己去实现。而match匹配输出靠的就是unapply
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class Customer (_name:String,_age:Int){
    val name=_name;
    val age=_age;

    }
    object Customer{
    def apply(_name: String, _age: Int): Customer = new Customer(_name, _age)
    // def unapply(arg: Customer): Option[(String, Int)] = {
    // if(arg ==null)
    // None
    // else
    // Some(arg.name,arg.age)
    // }
    // 没这个就会出下面的错误
    }

    object MyTest {
    def main(args: Array[String]): Unit = {
    val customer = Customer("zs", 20)
    customer match {
    case Customer(name,age) =>println(s"${name},${age}") // 这边出错了,找不到unapply
    case _=>println("not found")
    }
    }
    }

7.Scala函数

image-20240725113929142

  • 不用return ,直接把要返回的内容放最下面
  • 函数字面量其实就是函数名,类字面量是类的属性
A.参数传递与高阶函数
  • 传值调用(call-by-value) 传名调用(call-bh)

    image-20240725114141786

  • 高阶函数:参数可以为函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    object Demo {
    def abc(f:(String,Int) =>String) ={
    val res = f("李四", 20)
    println(res)
    }
    def ab(x:String,y:Int):String={
    "Hello,"+x+","+y.toString
    }
    def main(args: Array[String]): Unit = {
    abc(ab)
    }
    }
    // 输出 Hello,李四,20 abc是高阶函数
    • f:(String,Int) =>String代表,传入的参数是个函数,(String,Int)是传入函数的参数列表,=>String,这一段成为ab的方法原型

      上面图中f:=>Int是传入无参函数,输出为Int类型

B.参数可设置默认值
1
2
3
def ab(x:String="pty",y:Int=13):String={
"Hello,"+x+","+y.toString
}
C.匿名函数
1
2
3
4
5
6
7
8
9
10
def abc(f:(String,Int) =>String) ={
val res = f("李四", 20)
println(res)
}
def main(args: Array[String]): Unit = {
// abc(ab)
abc((x,y)=>{
s"Hello,${x},${y}"
})
}
  • abc包括的部分,如下,就是匿名函数,实际上就是Java中的Lambda表达式

    1
    2
    3
    (x,y)=>{
    s"Hello,${x},${y}"
    }
D.函数嵌套
  • 函数里可以包含方法,但是出了外层就不可用了
  • 不建议使用
E.函数柯里化
  • 每个参数都加个小括号

    1
    2
    3
    4
    5
    6
    7
    def mod(n:Int)(n2:Int):Int={
    n+n2
    }

    def main(args: Array[String]): Unit = {
    println(mod(10)(20))
    }
  • 可用于方法重载

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def mod(n:Int)(n2:Int)={
    n+n2
    }
    def mod1(n:Int)=mod(n)(20)
    def mod2(n2:Int)=mod(10)(n2)

    def main(args: Array[String]): Unit = {
    println(mod1(10))
    }
F.隐式参数

image-20240725144446418

  • 不管是全局还是局部只能有一个类型相似的隐式参数,如在这儿是个Int型,那么整个类中只能有这一个Int型的隐式参数

  • 和柯里化结合,会对最后一整个小括号里所有生效

  • 例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    object CurryingTest {
    implicit var abc:Int=20 // 不管全局还是局部一个类中只能一个同类型的隐式参数

    def mod(n:Int)(implicit n2:Int)={
    n+n2
    }

    def main(args: Array[String]): Unit = {
    println(mod(10)) // 出30
    println(mod(10)(40)) // 出50
    }
    }
  • 隐藏了方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Tools {
    def genericNum(str:String,i:Int)={
    str.hashCode()%i
    }
    }

    object CurryingTest {
    implicit var abc1:Tools=new Tools()
    def mod(str:String)(implicit gn:Tools) = {
    gn.genericNum(str,3)
    }
    def main(args: Array[String]): Unit = {
    println(mod("hello"))
    }
    }
G.隐式函数
  • 隐式函数也称隐式转换,使用implicit修饰的函数

  • 应用场景

    image-20240725153703103
  • 例子

    本来true+20是不可以的,但是隐式函数让Boolean类型的直接转换了

    1
    2
    3
    4
    5
    6
    7
    8
    implicit def fti(x:Boolean)=if(x) 1 else 0

    def main(args: Array[String]): Unit = {
    // println(mod("hello"))
    var flag=true;
    var num=20;
    println(flag+num)
    }
  • 任何值无法执行都变为数字,只有出错时才会调用隐式函数

    1
    implicit def stn(x:Any)=x.toString.toInt
H.函数闭包
  • 变量型的函数

    1
    2
    3
    4
    5
    def abc=(str:String)=>{
    s"Hello,${str}"
    }
    println(abc("sfdf"))
    // Hello,sfdf
  • 尽量不要用

(五)数组、元组与集合

  • scala中的语法:方法中只有一个参数可以省略.()
  • Map往往要用二元组来变化或者输出
  • scala算子,类似于流处理
  • String*类型的传值除了"a","b",还可以数组:_*

1.数组

  • 这边用的都是小括号来判断

    image-20240723142858382

  • 数组方法

    在终端中看

    1
    2
    val arr=Array(1,2,3,656,32,76,1)
    arr.按Tab
    • 迭代器用foreach来读取,Some(1)诸如此类用get来获取

    • def ++[B >: Int, That](that: scala.collection.GenTraversableOnce[B])(implicit bf: scala.collection.generic.CanBuildFrom[Array[Int],B,That]): That

      B和That都是泛型,但B要至少Int型的,即为Long。byte和short不可用。后面跟着个集合。集合的合并

      • 下面包括的其他知识点:
        • 偏函数
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      arr.++(Array(3,5,7))
      //输出res0: Array[Int] = Array(1, 2, 3, 656, 32, 76, 1, 3, 5, 7)
      arr.++(Array("aa","bb"))
      // 输出res1: Array[Any] = Array(1, 2, 3, 656, 32, 76, 1, aa, bb)
      arr ++ Array("aa","bb")
      // res2: Array[Any] = Array(1, 2, 3, 656, 32, 76, 1, aa, bb)
      arr ++ "cc"
      // res3: Array[AnyVal] = Array(1, 2, 3, 656, 32, 76, 1, c, c)
      arr ++ 100
      // 错误输出
      scala> 10 +: arr
      res6: Array[Int] = Array(10, 1, 2, 3, 656, 32, 76, 1)

      scala> arr :+ 10
      res7: Array[Int] = Array(1, 2, 3, 656, 32, 76, 1, 10)

      scala> lst ++: arr
      res8: Array[Int] = Array(4, 5, 68, 90, 1, 2, 3, 656, 32, 76, 1)
      scala> arr++: lst
      res9: List[Int] = List(1, 2, 3, 656, 32, 76, 1, 4, 5, 68, 90)
      //**`:`在的位置即为数组在的位置**,冒号右边的集合决定最终的结合
      // 光++也可以,而且以左边的为最终类型

      (0 /: arr)(_+_)
      res10: Int = 771 // 左子树相加,把数组里的内容全部相加
      (1 /: arr)(_*_)
      res12: Int = 9572352 // 左子树相乘,把数组里的内容全部相乘,前面的值是初始值
      (arr :\ 0)(_+_)
      res13: Int = 771 // 右子树相加,从右加到左

      scala> val sbi = new StringBuilder()
      sbi: StringBuilder =
      scala> arr.addString(sbi)
      res14: StringBuilder = 12365632761 // 化为字符串相连

      scala> arr.mkString(",")
      res15: String = 1,2,3,656,32,76,1 // 转为字符串,而且还可以设置分隔符

      始终对着集合

    • arr1.par.aggregate(10)(am,bm)10会成为第一个函数的第一个参数,每一个值是第一个函数中第二个值。第二个函数是前面计算结果的数组中的所有值,是多线程,一定要加这个par

      image-20240723152515201

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      scala> val arr1=Array(1,2,3,4,5)
      arr1: Array[Int] = Array(1, 2, 3, 4, 5)
      scala> def am(num1:Int,num2:Int):Int={
      | println(s"${num1}+${num2}")
      | return num1+num2;
      | }
      am: (num1: Int, num2: Int)Int
      scala> def bm(num1:Int,num2:Int):Int={
      | println(s"bm:${num1}+${num2}=${num1+num2}")
      | return num1+num2;
      | }
      bm: (num1: Int, num2: Int)Int
      scala> arr1.aggregate(10)(am,bm)
      10+1
      11+2
      13+3
      16+4
      20+5
      res16: Int = 25
      scala> arr1.par.aggregate(10)(am,bm)
      // 下面这些顺序都不一定
      10+4
      10+2
      10+3
      10+1
      10+5
      bm:11+12=23
      bm:14+15=29
      bm:13+29=42
      bm:23+42=65
      res17: Int = 65

      // 上面这些过程,可以简化为下面的
      scala> arr1.par.aggregate(10)(_+_,_+_)
      res48: Int = 65
      // 但是结果不一定为65出错,因为多线程太快了,而前面的每步骤print减缓了速度,大部分情况都是对的

      //apply 取值操作
      scala> arr1(2)
      res83: Int = 3
      scala> arr1.apply(2)
      res84: Int = 3

      //charAt 按数字取字符
      var str=Array('a','c','d')
      str: Array[Char] = Array(a, c, d)
      scala> str.charAt(1)
      res85: Char = c

      // 赋值只是地址
      scala> var arr2=arr1
      arr2: Array[Int] = Array(1, 2, 3, 4, 5)
      scala> arr2(2)=100
      scala> arr1
      res89: Array[Int] = Array(1, 2, 100, 4, 5)
      // 用clone()就会出新的
      scala> val arr2=arr1.clone()
      arr2: Array[Int] = Array(1, 2, 100, 4, 5)
      scala> arr2(1)=44
      scala> arr1
      res91: Array[Int] = Array(1, 2, 100, 4, 5)
      scala> arr2
      res92: Array[Int] = Array(1, 44, 100, 4, 5)
    • collect,内部为偏心函数PartialFunction,只要某些值 可对多种不同的if内部数据进行处理和输出。只处理部分

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
        // 只要偶数,并且将偶数*10
      scala> arr1
      res93: Array[Int] = Array(1, 2, 100, 4, 5)
      scala> arr1.collect{case x if(x%2==0)=>x*10}
      res94: Array[Int] = Array(20, 1000, 40)
      scala> arr1.collect({case x if(x%2==0)=>x*10})
      res95: Array[Int] = Array(20, 1000, 40)
      // 使用偏心函数
      scala> val pianxin:PartialFunction[Int,Int]={
      | case x if(x%2==0) => x*10
      | case x=>x+3
      | }
      pianxin: PartialFunction[Int,Int] = <function1>
      scala> arr1.collect(pianxin)
      res96: Array[Int] = Array(4, 20, 1000, 40, 8)
      scala> arr1.collect({case x if(x%2==0)=>x*10 case x if(x%2==1)=>x*100000})
      res97: Array[Int] = Array(100000, 20, 1000, 40, 500000)

      // combinations是将数据按照括号中的数字进行组合,这边是两两组合,出来是个迭代器
      scala> arr1.combinations(2).foreach(x=>println(x.mkString(",")))
      1,2
      1,100
      1,4
      1,5
      2,100
      2,4
      2,5
      100,4
      100,5
      4,5

      // 是否在数组中
      scala> arr1.contains(100)
      res101: Boolean = true
      scala> arr1.contains(101)
      res102: Boolean = false

      // 查找序列,而且必须连续,不可相反,必须一模一样
      scala> arr1
      res103: Array[Int] = Array(1, 2, 100, 4, 5)
      scala> arr1.containsSlice(List(100,2))
      res104: Boolean = false
      scala> arr1.containsSlice(List(2,100))
      res105: Boolean = true

      // 数组拷贝
      scala> arr1
      res106: Array[Int] = Array(1, 2, 100, 4, 5)
      scala> val arr3=new Array[Int](10)
      arr3: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
      scala> arr1.copyToArray(arr3,2,3)
      scala> arr3
      res108: Array[Int] = Array(0, 0, 1, 2, 100, 0, 0, 0, 0, 0)

      //copyToBuffer 拷贝到集合中
      scala> import scala.collection.mutable.Buffer
      import scala.collection.mutable.Buffer
      scala> val bf = Buffer[Int]()
      bf: scala.collection.mutable.Buffer[Int] = ArrayBuffer()
      scala> arr1.copyToBuffer(bf)
      scala> bf
      res113: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 100, 4, 5)

      //corresponds 相同数量序列元素一一对比大小,是否符合条件
      scala> arr1
      res115: Array[Int] = Array(1, 2, 100, 4, 5)
      scala> arr2
      res116: Array[Int] = Array(1, 44, 100, 4, 5)
      scala> arr1.corresponds(arr2)(_==_)
      res117: Boolean = false
      scala> arr1.corresponds(arr2)(_<=_)
      res118: Boolean = true

      //count 统计符合条件的总数
      scala> arr2.count(x=>x%2==0) // 偶数
      res119: Int = 3
      scala> arr2.count(x=>true) // 全部
      res120: Int = 5
      // arr2.size也是统计整个长度

      //diff 计算当前数组与另一个数组的不同。将当前数组中没有在另一个数组中出现的元素返回
      scala> val arr4=Array(1,100,6,7,99)
      arr4: Array[Int] = Array(1, 100, 6, 7, 99)
      scala> arr1
      res121: Array[Int] = Array(1, 2, 100, 4, 5)
      scala> arr1.diff(arr4)
      res122: Array[Int] = Array(2, 4, 5) // arr1中4没有的
      scala> arr1.diff(arr4) ++: arr4.diff(arr1)
      res123: Array[Int] = Array(2, 4, 5, 6, 7, 99)// 两张表中不同的部分

      //distinct 去重
      scala> val arr5=Array(1,2,1,1,235)
      arr5: Array[Int] = Array(1, 2, 1, 1, 235)
      scala> arr5.distinct
      res125: Array[Int] = Array(1, 2, 235)

      //drop 功能同 drop,去掉开头几个。dropRight去掉尾部的 n 个元素
      scala> arr1
      res126: Array[Int] = Array(1, 2, 100, 4, 5)
      scala> arr1.dropRight(2)
      res127: Array[Int] = Array(1, 2, 100)

      //dropWhile 只删到第一个不满足条件的数据
      arr1.dropWhile(x=>x<50)
      res128: Array[Int] = Array(100, 4, 5)
      scala> arr1.dropWhile(x=>x<2)
      res129: Array[Int] = Array(2, 100, 4, 5)
      scala> arr1.dropWhile(x=>x<4)
      res130: Array[Int] = Array(100, 4, 5)

      //endsWith 是否以某个序列结尾
      scala> arr1.endsWith(List(4,5))
      res131: Boolean = true

      //exists 是否存在符合条件的
      scala> arr1
      res126: Array[Int] = Array(1, 2, 100, 4, 5)
      scala> arr1.exists(x=>x>100)
      res133: Boolean = false
      scala> arr1.exists(x=>x>50)
      res134: Boolean = true

      //filter和filterNot 满足条件和不满足的
      scala> arr1
      res126: Array[Int] = Array(1, 2, 100, 4, 5)
      scala> arr1.filter(x=>x%2==0)
      res135: Array[Int] = Array(2, 100, 4)
      scala> arr1.filterNot(x=>x%2==0)
      res136: Array[Int] = Array(1, 5)

      //find 第一个满足条件的
      scala> arr1.find(x=>x>3)
      res137: Option[Int] = Some(100)
      scala> arr1.find(x=>x>100)
      res140: Option[Int] = None

      //flatten 多为数组降维
      scala> var twoarr=Array(Array(1,2,3),Array(4,5,6))
      twoarr: Array[Array[Int]] = Array(Array(1, 2, 3), Array(4, 5, 6))
      scala> twoarr.flatten
      res141: Array[Int] = Array(1, 2, 3, 4, 5, 6)

      //flatMap 相当于map再flatten
      scala> val words=Array("Hello world", "Hello spark")
      words: Array[String] = Array(Hello world, Hello spark)
      scala> words.map(line=>line.split(" "))
      res143: Array[Array[String]] = Array(Array(Hello, world), Array(Hello, spark))
      scala> words.map(line=>line.split(" ")).flatten
      res144: Array[String] = Array(Hello, world, Hello, spark)
      scala> words.flatMap(line=>line.split(" "))
      res145: Array[String] = Array(Hello, world, Hello, spark)

      // scala中使用map,map中用Some包裹返回时返回None就没有返回

      // 分组统计单词 元组tuple用_1,_2来出数据,map后flatten
      scala> words.flatMap(line=>line.split(" ")).groupBy(x=>x).foreach(x=>println(x._1,x._2.size))
      (spark,1)
      (world,1)
      (Hello,2)
      scala> arr.groupBy(x=>{
      | if(x%2==0){
      | "even"
      | }else{
      | "odd"
      | }
      | })
      res0: scala.collection.immutable.Map[String,Array[Int]] = Map(odd -> Array(1, 3435, 89), even -> Array(22, 56, 8))



    • match相当于Java 的switch,但是功能有增强。_相当于其他。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
      171
      172
      173
      174
      175
      176
      177
      178
      179
      180
      181
      182
      183
      184
      185
      186
      187
      188
      189
      190
      191
      192
      193
      194
      195
      196
      197
      198
      199
      200
      201
      202
      203
      204
      205
      206
      207
      208
      209
      210
      211
      212
      213
      214
      215
      216
      217
      218
      219
      220
      221
      222
      223
      224
      225
      226
      227
      228
      229
      230
      231
      232
      233
      234
      235
      236
      237
      238
      239
      240
      241
      242
      243
      244
      245
      246
      247
      248
      249
      250
      251
      252
      253
      254
      255
      256
      257
      258
      259
      260
      261
      262
      263
      264
      265
      266
      267
      268
      269
      270
      271
      272
      273
      274
      275
      276
      277
      278
      279
      280
      281
      282
      283
      284
      285
      286
      287
      288
      289
      290
      291
      292
      293
      294
      295
      296
      297
      298
      299
      300
      301
      302
      303
      304
      305
      306
      307
      308
      309
      310
      311
      312
      313
      314
      315
      316
      317
      318
      319
      320
      321
      322
      323
      324
      325
      326
      327
      328
      329
      330
      331
      332
      333
      334
      335
      336
      337
      338
      339
      340
      341
      342
      343
      344
      345
      346
      347
      348
      349
      350
      351
      352
      353
      354
      355
      356
      357
      358
      359
      360
      361
      362
      363
      364
      365
      366
      367
      368
      369
      370
      371
      372
      373
      374
      375
      376
      377
      378
      379
      380
      381
      382
      383
      384
      385
      scala> arr
      res6: Array[Int] = Array(1, 22, 3435, 56, 8, 89)

      // groupBy加match
      scala> arr.groupBy(x=>{
      | x match {
      | case i if i%2==0 => "even"
      | case _ => "odd"
      | }
      | })
      res2: scala.collection.immutable.Map[String,Array[Int]] = Map(odd -> Array(1, 3435, 89), even -> Array(22, 56, 8))

      scala> arr.groupBy(x=>x match{
      | case i if i%2==0 => "even"
      | case _ => "odd"
      | })
      res3: scala.collection.immutable.Map[String,Array[Int]] = Map(odd -> Array(1, 3435, 89), even -> Array(22, 56, 8))

      // 按几个元素分组
      scala> arr
      res6: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.grouped(3).foreach(x=>println(x.mkString(",")))
      1,22,3435
      56,8,89

      // 判断是否有界限,流是没有界限的
      scala> arr.hasDefiniteSize
      res8: Boolean = true

      // 看第一个值
      scala> arr
      res10: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.head
      res11: Int = 1
      scala> val arr1=Array()
      arr1: Array[Nothing] = Array()
      scala> arr1.head
      <console>:13: error: value head is not a member of Array[Nothing]
      arr1.head
      // 无值会出错,因此应该先判断一下
      scala> val arr1:Array[Int]=Array[Int]()
      arr1: Array[Int] = Array()
      scala> arr1.headOption
      res16: Option[Int] = None

      scala> arr.headOption
      res18: Option[Int] = Some(1)
      scala> arr.headOption.get
      res19: Int = 1

      // 找数据位置
      scala> arr.indexOf(3234)
      res20: Int = -1
      scala> arr
      res21: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.indexOf(3435)
      res22: Int = 2

      // 序列所在位置
      scala> arr
      res21: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.indexOfSlice(Array(3435,22))
      res24: Int = -1
      scala> arr.indexOfSlice(Array(22,3435))
      res25: Int = 1

      // 满足条件的第一个值的下标
      scala> arr
      res27: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.indexWhere(x=>x%2==0)
      res26: Int = 1

      // 找离0.25最近的点
      scala> var my=Array(0.21169, 0.61391, 0.6341, 0.0131, 0.16541, 0.5645, 0.5742)
      my: Array[Double] = Array(0.21169, 0.61391, 0.6341, 0.0131, 0.16541, 0.5645, 0.5742)
      scala> my.map(x=>(x-0.52).abs).min
      res32: Double = 0.044499999999999984
      scala> my(res31.indexWhere(x=>x==res32))
      res34: Double = 0.5645

      // 返回下标
      scala> arr
      res35: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.indices
      res36: scala.collection.immutable.Range = Range(0, 1, 2, 3, 4, 5)

      // 去掉最后一个数
      scala> my
      res37: Array[Double] = Array(0.21169, 0.61391, 0.6341, 0.0131, 0.16541, 0.5645, 0.5742)
      scala> my.init
      res38: Array[Double] = Array(0.21169, 0.61391, 0.6341, 0.0131, 0.16541, 0.5645)

      // 每次减一个
      scala> arr.inits.foreach(x=>println(x.mkString(",")))
      1,22,3435,56,8,89
      1,22,3435,56,8
      1,22,3435,56
      1,22,3435
      1,22
      1

      // 交集
      scala> arr
      res47: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> val arr3=Array(1,3435,55,68,56,1232)
      arr3: Array[Int] = Array(1, 3435, 55, 68, 56, 1232)
      scala> arr.intersect(arr3)
      res48: Array[Int] = Array(1, 3435, 56)

      // 是否有该下标位置
      scala> arr
      res50: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.isDefinedAt(7)
      res51: Boolean = false
      scala> arr.isDefinedAt(6)
      res52: Boolean = false
      scala> arr.isDefinedAt(5)
      res53: Boolean = true

      // 集合是否为空
      scala> arr1
      res54: Array[Int] = Array()
      scala> arr1.isEmpty
      res55: Boolean = true

      // 是否能反复遍历,iterator就不能
      scala> arr1.isTraversableAgain
      res57: Boolean = true

      // 按照数组生成一个迭代器
      scala> arr.iterator
      res58: Iterator[Int] = non-empty iterator

      // 取最后一个值
      scala> arr.last
      res60: Int = 89

      // 是否有最后一个值
      scala> arr.lastOption
      res61: Option[Int] = Some(89)

      scala> arr
      res63: Array[Int] = Array(1, 22, 3435, 56, 8, 89)

      // 从右往左第一个该数
      scala> arr.lastIndexOf(56)
      res64: Int = 3
      lastIndexWhere // 按要求从右往左搜索

      // Scala中一样,再Java中size是有数据的
      scala> arr.length
      res65: Int = 6
      scala> arr.size
      res66: Int = 6

      // 数组长度减去给的值,结果为差额
      scala> arr
      res70: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.lengthCompare(6)
      res71: Int = 0
      scala> arr.lengthCompare(7)
      res72: Int = -1
      scala> arr.lengthCompare(3)
      res73: Int = 3

      // 是不是不空
      scala> arr
      res88: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.nonEmpty
      res89: Boolean = true
      scala> arr1
      res90: Array[Int] = Array()
      scala> arr1.nonEmpty
      res91: Boolean = false

      // 右补齐
      scala> arr
      res92: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.padTo(10,0)
      res93: Array[Int] = Array(1, 22, 3435, 56, 8, 89, 0, 0, 0, 0)
      // 左补齐
      scala> arr.reverse.padTo(10,0).reverse
      res96: Array[Int] = Array(0, 0, 0, 0, 1, 22, 3435, 56, 8, 89)
      scala> "hello".reverse.padTo(10,0).reverse.mkString("")
      res97: String = 00000hello
      // 日期补0
      scala> "2017-1-15".split("-").map(x=>x.reverse.padTo(2,0).reverse.mkString("")).mkString("-")
      res106: String = 2017-01-15

      // 分区,只能分两个
      scala> arr.partition(x=>x%2==0)
      res108: (Array[Int], Array[Int]) = (Array(22, 56, 8),Array(1, 3435, 89))

      // 批量替换,从第一个数字开始,往后多少个数的被替换成
      scala> my
      res111: Array[Double] = Array(0.21169, 0.61391, 0.6341, 0.0131, 0.16541, 0.5645, 0.5742)
      scala> arr
      res112: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.patch(1,my,3)
      res113: Array[AnyVal] = Array(1, 0.21169, 0.61391, 0.6341, 0.0131, 0.16541, 0.5645, 0.5742, 8, 89)

      // 所有数据的各种排列组合
      arr.permutations.toList.foreach(x=>println(x.mkString(",")))

      // 获得满足条件的前缀长度
      scala> arr
      res117: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.prefixLength(x=>x<1000)
      res118: Int = 2

      // 乘积
      scala> arr.product
      res119: Int = -1281840256

      // 构建左子树,且不需要初始值
      scala> arr
      res120: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.reduce(_+_)
      res121: Int = 3611
      // 构建右子树
      scala> arr.reduceRight(_+_)
      res122: Int = 3611

      // 先做map再做reverse
      scala> arr
      res124: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.reverseMap(x=>x*10)
      res125: Array[Int] = Array(890, 80, 560, 34350, 220, 10)

      // 是否数组内容相同
      scala> arr
      res126: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr4
      res127: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.sameElements(arr4)
      res128: Boolean = true
      // 顺序也得完全一样
      scala> var arr5=Array(1, 22, 3435, 56, 89,8)
      arr5: Array[Int] = Array(1, 22, 3435, 56, 89, 8)
      scala> arr
      res129: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.sameElements(arr5)
      res130: Boolean = false

      // 初始值一路加过去
      scala> arr.scan(5)(_+_)
      res136: Array[Int] = Array(5, 6, 28, 3463, 3519, 3527, 3616)

      // segmentLength 从序列的 from 处开始向后查找,所有满足 p 的连续元素的长度
      val a = Array(1,2,3,1,1,1,1,1,4,5)
      val b = a.segmentLength( {x:Int => x < 3},3) // 5
      scala> val b = a.segmentLength( {x:Int => x < 3},2)
      b: Int = 0
      // 0

      // 切片 左包右不包
      scala> arr
      res139: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.slice(1,3)
      res140: Array[Int] = Array(22, 3435)

      // 窗口滑动
      scala> arr
      res142: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.sliding(3).foreach(x=>println(x.mkString(",")))
      1,22,3435
      22,3435,56
      3435,56,8
      56,8,89
      // 步长为2的滑动
      scala> arr.sliding(3,2).foreach(x=>println(x.mkString(",")))
      1,22,3435
      3435,56,8
      8,89

      // 排序 升序和降序,注意:降序的-号要空一格
      scala> arr.sortBy(x=>x)
      res0: Array[Int] = Array(1, 8, 22, 56, 89, 3435)
      scala> arr.sortBy(x=> -x)
      res1: Array[Int] = Array(3435, 89, 56, 22, 8, 1)
      // 固定数组排序
      scala> arr.sorted
      res2: Array[Int] = Array(1, 8, 22, 56, 89, 3435)

      // 按第一个遇到不满足条件的分割
      scala> arr
      res4: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.span(x=>x<1000)
      res5: (Array[Int], Array[Int]) = (Array(1, 22),Array(3435, 56, 8, 89))
      scala> arr.span(_<1000)
      res6: (Array[Int], Array[Int]) = (Array(1, 22),Array(3435, 56, 8, 89))

      // 从某个位置开始分割,分割的位置所在值在后面
      scala> arr
      res8: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.splitAt(3)
      res9: (Array[Int], Array[Int]) = (Array(1, 22, 3435),Array(56, 8, 89))

      // 是否以什么开头
      scala> arr
      res11: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.startsWith(Array(1,22))
      res12: Boolean = true
      scala> arr.startsWith(Array(22))
      res13: Boolean = false
      // 可从某个位置开始判定
      scala> arr.startsWith(Array(22),1)
      res14: Boolean = true

      // 除了第一个
      scala> arr
      res16: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.tail
      res17: Array[Int] = Array(22, 3435, 56, 8, 89)

      // 拿左边几个
      scala> arr.take(3)
      res18: Array[Int] = Array(1, 22, 3435)

      // 拿右边几个
      scala> arr.takeRight(3)
      res19: Array[Int] = Array(56, 8, 89)

      scala> arr
      res21: Array[Int] = Array(1, 22, 3435, 56, 8, 89)

      // 拿数据直到不满足
      scala> arr
      res21: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.takeWhile(_<100)
      res22: Array[Int] = Array(1, 22)

      // 类型可以不断转换
      scala> arr.toList
      res23: List[Int] = List(1, 22, 3435, 56, 8, 89)
      scala> arr.toBuffer
      res24: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 22, 3435, 56, 8, 89)
      scala> arr.toBuffer.toArray
      res25: Array[Int] = Array(1, 22, 3435, 56, 8, 89)

      // toMap要用数组里放元组的方式
      scala> arr
      res28: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.toMap
      <console>:13: error: Cannot prove that Int <:< (T, U).
      arr.toMap
      ^
      scala> val arr5=Array(("name","zhangsan"),("age","20"))
      arr5: Array[(String, String)] = Array((name,zhangsan), (age,20))
      scala> arr5.toMap
      res30: scala.collection.immutable.Map[String,String] = Map(name -> zhangsan, age -> 20)

      // 矩阵转置
      scala> val arr5=Array(Array("name","zhangsan"),Array("age","20"))
      arr5: Array[Array[String]] = Array(Array(name, zhangsan), Array(age, 20))
      scala> arr5.transpose
      res34: Array[Array[String]] = Array(Array(name, age), Array(zhangsan, 20))

      // union和++一样

      // 2行2列转置
      arr.unzip
      // 3行3列转置
      arr.unzip3

      // 改某位的值
      scala> arr
      res36: Array[Int] = Array(1, 22, 3435, 56, 8, 89)
      scala> arr.update(2,345)
      scala> arr
      res38: Array[Int] = Array(1, 22, 345, 56, 8, 89)

      // 截取,左包右不包
      scala> arr
      res39: Array[Int] = Array(1, 22, 345, 56, 8, 89)
      scala> arr.view(1,4).toList
      res40: List[Int] = List(22, 345, 56)

      // 对应位置按对拿出,按短的算
      scala> arr
      res42: Array[Int] = Array(1, 22, 345, 56, 8, 89)
      scala> val arr2=Array(33,345,5656)
      arr2: Array[Int] = Array(33, 345, 5656)
      scala> arr.zip(arr2)
      res43: Array[(Int, Int)] = Array((1,33), (22,345), (345,5656))

2.元组

  • 特点

    • 可以包含不同类型的元素

    • 最多支持22个元素

    • 使用下划线_访问元素,_1是第一个元素

    • 元组中值不可更改

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      scala> val tup=(1,"zs",20,175.2,"1999-10-12")
      tup: (Int, String, Int, Double, String) = (1,zs,20,175.2,1999-10-12)

      scala> tup._1
      res44: Int = 1

      scala> tup._1=2
      <console>:12: error: reassignment to val
      tup._1=2
      ^
    • 主要就用productIterator变成迭代器来使用

    • 奇怪语法

      一次性定义很多变量

      1
      2
      3
      4
      5
      6
      7
      8
      scala> val tup=(1,"zs",20,175.2,"1999-10-12")
      tup: (Int, String, Int, Double, String) = (1,zs,20,175.2,1999-10-12)
      scala> val (stuid,stuname,stuage,high,birthday)=tup
      stuid: Int = 1
      stuname: String = zs
      stuage: Int = 20
      high: Double = 175.2
      birthday: String = 1999-10-12

3.集合

image-20240724142148784

A.前期
  • Traversable是顶级集合类

  • 集合类别

    • 不可变集合

      • scala.collection.immutable,默认Scala选择不可变集合

      • 例子

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        scala> val aa=List(1,2,3)
        aa: List[Int] = List(1, 2, 3)

        scala> aa.getClass
        res47: Class[_ <: List[Int]] = class scala.collection.immutable.$colon$colon

        scala> aa(1)=111
        <console>:13: error: value update is not a member of List[Int]
        aa(1)=111
        ^
      • image-20240724143315963

        上面全是类 常用Set Seq Map HashMap

    • 可变集合:可以修改、添加或移除一个集合的元素

      • scala.colection.mutable

      • 方法里带=

      • 例子

        1
        2
        3
        4
        5
        6
        7
        8
        scala> val lb = scala.collection.mutable.ListBuffer(1,2,3)
        lb: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3)

        scala> lb += 22
        res49: lb.type = ListBuffer(1, 2, 3, 22)

        scala> lb.+=(22)
        res50: lb.type = ListBuffer(1, 2, 3, 22, 22)
      • image-20240724143603145

        常用Map Seq Set ArrayBuffer ListBuffer HashMap StringBuffer

B.常用集合

image-20240724144009340

C.Map

image-20240724144243966

  • 拿值要m(key) 或者 m.get(key).get

(六)练习

  • 工程文件为scala/myexp

  • 原始数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    // student
    01,赵雷,1990-01-01,男
    02,钱电,1990-12-21,男
    03,孙风,1990-05-20,男
    04,李云,1990-08-06,男
    05,周梅,1991-12-01,女
    06,吴兰,1992-03-01,女
    07,郑竹,1989-07-01,女
    08,王菊,1990-01-20,女

    // sc
    01,01,80
    01,02,90
    01,03,99
    02,01,70
    02,02,60
    02,03,80
    03,01,80
    03,02,80
    03,03,80
    04,01,50
    04,02,30
    04,03,20
    05,01,76
    05,02,87
    06,01,31
    06,03,34
    07,02,89
    07,03,98

    // Course
    01,语文,02
    02,数学,01
    03,英语,03

    // teacherp
    01,张三
    02,李四
    03,王五
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    // 读数据,用专门的函数,以及实体类来存储
    // 四个实体类
    case class Course(cid:String,cname:String,tid:String)
    case class Score(sid:String,cid:String,score:Int)
    case class Student(sid:String,name:String,birthday:String,gender:String)
    case class Teacher(tid:String,tname:String)


    // 枚举类
    object TableEnum extends Enumeration {
    type TableEnum = Value
    val SCORE,STUDENT,TEACHER,COURSE=Value
    }


    // 主类中,相关函数和使用
    object Exp1To5 {
    def readTxtToBuffer(path: String,model:TableEnum): ListBuffer[Any] = {
    val reader = new BufferedReader(new FileReader(path));
    var scData = ListBuffer[Any]();
    var line: String = reader.readLine();
    while (line != null) {
    val infos = line.split(",")
    model match{
    case SCORE=> scData+=Score(infos(0),infos(1),infos(2).toInt)
    case TEACHER=> scData+=Teacher(infos(0),infos(1))
    case STUDENT => scData+=Student(infos(0),infos(1),infos(2),infos(3))
    case COURSE => scData+=Course(infos(0),infos(1),infos(2))
    }
    line = reader.readLine();
    }
    reader.close();
    scData
    }

    def main(args: Array[String]): Unit = {
    val lb = readTxtToBuffer("E:\\ProgramFile\\BigDataStudy\\data\\scalaexp\\sc.txt",SCORE);
    lb.map(x => {
    val tuple = x.asInstanceOf[Score]
    tuple
    }).foreach(x=>println(x))
    }
    }
    • 解释
      - 枚举类要继承Enumeration

第1题

查询”01”课程比”02”课程成绩高的学生的信息及课程分数

  • 法1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 1. 先查出所有01课程的学员及分数
    val oneSc = scData.filter(x=>x._2.equals("01"));
    val twoSc = scData.filter(x=>x._2.equals("02"));
    println(oneSc)
    println(twoSc)
    // 2.使用偏函数遍历01课程集合 再02课程中进行搜索
    var bb=oneSc.flatMap(tup=>{
    twoSc.map(tup02=> {
    if (tup._1.equals(tup02._1)) {
    Array(tup._1,tup._3,tup02._3)
    } else{
    Array()
    }
    })
    }).filter(x=>x.size!=0 && x(1).toString.toInt > x(2).toString.toInt).map(x=>(x(0),x(1),x(2)))
    println(bb)
  • 法2

    1
    2
    3
    4
    5
    val bb = scData.filter(x => x._2.equals("01") || x._2.equals("02"))
    .groupBy(x => x._1).map(x=>x._2.sortBy(e=>e._2))
    .filter(p=>p.size==2 && p(0)._3>p(1)._3)

    println(bb)

第3题

  • 第3题:查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
val scorelb = readTxtToBuffer("E:\\ProgramFile\\BigDataStudy\\data\\scalaexp\\sc.txt",SCORE)
.map(_.asInstanceOf[Score]);
val stulb = readTxtToBuffer("E:\\ProgramFile\\BigDataStudy\\data\\scalaexp\\student.txt",STUDENT)
.map(s=>{
val stu = s.asInstanceOf[Student];
(stu.sid,(stu.name,stu.gender,stu.birthday))
}).toMap
// 第3题:查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
val res = scorelb.groupBy(_.sid).mapValues(lb => {
var cnt_score = 0;
lb.foreach(s => cnt_score += s.score)
cnt_score / lb.size
}).filter(x => x._2 >= 60)
.map(sc=>{
// 获取学院的信息
val stuinfo = stulb.get(sc._1);
(stuinfo.get,sc._2);
})

println(res)

第5题

  • 第5题:查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    val scorelb = readTxtToBuffer("E:\\ProgramFile\\BigDataStudy\\data\\scalaexp\\sc.txt",SCORE)
    .map(_.asInstanceOf[Score]);
    val stulb = readTxtToBuffer("E:\\ProgramFile\\BigDataStudy\\data\\scalaexp\\student.txt",STUDENT)
    .map(s=>{
    val stu = s.asInstanceOf[Student];
    (stu.sid,stu)
    }).toMap

    val res = scorelb.groupBy(_.sid).map(lb=>{
    var cnt_score = 0;
    lb._2.foreach(s=>cnt_score+=s.score)
    (lb._1,(lb._2.size,cnt_score))
    })
    val res1 = stulb.map(x => {
    val findScore = res.getOrElse(x._1, (0, 0));
    (x._1,x._2.name, findScore._1,findScore._2)
    })
    println(res1)
  • 要进行一个外联,因为可能有人没有考,用getOrElse方式取值

第7题

  • 第7题:查询学过”张三”老师授课的同学的信息

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // 第7题:查询学过"张三"老师授课的同学的信息
    val scorelb = readTxtToBuffer("E:\\ProgramFile\\BigDataStudy\\data\\scalaexp\\sc.txt",SCORE)
    .map(_.asInstanceOf[Score]);
    val stulb = readTxtToBuffer("E:\\ProgramFile\\BigDataStudy\\data\\scalaexp\\student.txt",STUDENT)
    .map(s=>{
    val stu = s.asInstanceOf[Student];
    (stu.sid,stu)
    }).toMap
    val tealb = readTxtToBuffer("E:\\ProgramFile\\BigDataStudy\\data\\scalaexp\\teacher.txt",TEACHER)
    .map(_.asInstanceOf[Teacher]);
    val courselb = readTxtToBuffer("E:\\ProgramFile\\BigDataStudy\\data\\scalaexp\\course.txt",COURSE)
    .map(_.asInstanceOf[Course]);
    val teacher = tealb.filter(x => x.tname.equals("张三"))(0)
    val courses = courselb.filter(x => x.tid.equals(teacher.tid))
    .map(x=>(x.cid,x.cname)).toMap

    println(courses)
    val scc = scorelb.collect({
    case x if (courses.get(x.cid) != None) => x.sid
    }).distinct.map(stuid=>stulb.get(stuid).get)
    println(scc)

其他

(七)其他语法

  • map(_.asInstanceOf[类型])强转,对集合中每个值墙砖

  • 类型Any相当于Java中的Object

  • 二元组和Map可以相互转化

  • 如果lambda只有一条语句,省略{},可从x=>{x<100}变为x=>x<100

    如果参数只用一次可从x=>x<100变为_<100

  • 每个单词开头大写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def toTitle(str:String): String ={
    val pattern = "([a-zA-Z']*[^a-z|A-Z|']+)|[a-zA-Z']+".r;
    val li = pattern.findAllIn(str)
    .map(x=>x(0).toUpper+x.toLowerCase.substring(1)).mkString;
    li;
    }
    def main(args: Array[String]): Unit = {
    println(toTitle("what do you want to do?let's go"))
    }
    // 出What Do You Want To Do?Let's Go

(八)面向对象编程

  • image-20240725161121279

1.类

  • 初步
    • 类通过class关键字定义
    • 类通过new关键字创建实例
    • 类拥有成员变量和方法
    • 类的成员默认为public,也支持private、protected
    • 类中无法定义静态成员变量和方法
    • 类无需明确定义构造方法,通过构造参数列表声明为类的一部分

A.类访问修饰符

image-20240725161406346

B.类的定义

  • 主构造器,辅助构造器

    image-20240725161512466

  • 参数构造直接在后面用括号

  • class中不允许有静态方法,要在object中new

  • 例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class FirstClazz(name:String,age:Int){
    val username=name;
    val userage=age;

    def this()={
    this("zs",20)
    }

    def add(num1:Int,num2:Int)={
    s"${num1}+${num2}=${num1+num2},${username},${userage}"
    }
    }

    object MyMain {
    def main(args: Array[String]): Unit = {
    val fc = new FirstClazz()
    println(fc.add(10, 34))
    }
    }
    // 10+34=44,zs,20

2.抽象类

image-20240725163528056

3.单例对象

  • Scala的类中无法定义静态成员,像Java一样表达类的静态成员变量、成员方法与静态代码块?
  • Scala解决方案:单例对象
    • 使用“object”关键字声明,可包含变量、方法与代码定义
    • 单例对象中的成员变量、成员方法通过单例对象名直接调用
    • 单例对象第一次被访问时初始化,并执行全部代码块
    • 单例对象不能new,且无构造参数
    • 程序入口main()方法必须定义在单例对象中
    • 单例对象与同名类定义在同一文件中时形成绑定关系

A.伴生对象

  • 伴生类和伴生对象,名字要相同,要在同一个文件中

  • apply是直接弹出来的

  • 例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import com.njupt.myexp.MyClassObject.uname
    // 伴生类
    class MyClassObject(name:String) {
    val username=name;

    def printName()={
    print(s"Hello,${username},${uname}")
    }
    }
    // 伴生对象
    object MyClassObject{
    def uname="ls"
    def apply(name: String): MyClassObject = new MyClassObject(name)
    def unapply(arg: MyClassObject): Option[String] = Some(uname) // 只能拿到这边对象的
    }


    // 在其他文件中 两种方法都可以使用
    // val za = new MyClassObject("za")
    val za = MyClassObject("za")
    za.printName()
    // 输出Hello,za,ls
    • 解释

      • 类可以输出对象中的方法

        方法不能直接调用类中的东西

        上面那个uname

      • apply是相当于在外部不要new

      • unapply相当于是toString

4.隐式类

  • 可以增强功能,但是不用改原本的类

  • 可以看到ImClazz原本没有xxx()但是可用,在上面隐式类中参数要是相应类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class ImClazz {
    def sayHello()={
    println("Hello")
    }
    }

    object MyMain {
    implicit class AddFunc(xx:ImClazz) {
    def xxx():Unit={
    println("xxx")
    }
    }

    def main(args: Array[String]): Unit = {
    val ic = new ImClazz();
    ic.sayHello();
    ic.xxx();
    }
    }

5.特质trait

A.概述与概念
  • Scala中没有接口(interface)的概念
  • 特质用于在类之间共享程序接口和字段,类似Java接口
  • 特质是字段和方法的集合,可以提供字段和方法实现
  • 类和单例对象都可以扩展特质(extends)
  • 特质不能被实例化,因此没有构造参数,类似Java接口
  • 特质使用”trait”关键字定义
  • 实现特质中的方法使用”override”
  • 可实现动态混入特质
B.混入特质

image-20240726093825303

类能继承它,它也能继承普通类

C.动态混入特质
  • image-20240726102123617

    类似于接口

    动态混入,一个类中只能一个,而且,但是可以让多个trait互相继承,一次性导入

  • 代码样例,重写前面练习中的读入文件内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    trait DataChangeTrait [T]{
    def change(line:String):T
    }

    trait ScoreChangeTrait extends DataChangeTrait[Score]{
    override def change(line: String): Score = {
    val infos = line.split(",")
    Score(infos(0),infos(1),infos(2).toInt)
    }
    }

    trait StudentChangeTrait extends DataChangeTrait[Student]{
    override def change(line: String): Student = {
    val infos = line.split(",")
    Student(infos(0),infos(1),infos(2),infos(3))
    }
    }

    class DataChangeTool[T] {
    self:DataChangeTrait[T] =>

    def readTxtToBuffer(path: String): ListBuffer[T] = {
    val reader = new BufferedReader(new FileReader(path));
    val scData = ListBuffer[T]();
    var line: String = reader.readLine();
    while (line != null) {
    scData += change(line);
    line = reader.readLine();
    }
    reader.close();
    scData
    }
    }

    object MyTest {
    def main(args: Array[String]): Unit = {
    val scores = (new DataChangeTool[Score]() with ScoreChangeTrait).readTxtToBuffer("E:\\ProgramFile\\BigDataStudy\\data\\scalaexp\\sc.txt")
    println(scores)
    val stus = (new DataChangeTool[Student]() with StudentChangeTrait).readTxtToBuffer("E:\\ProgramFile\\BigDataStudy\\data\\scalaexp\\student.txt")
    println(stus)
    }
    }
    // 数据到这儿把两个文件的读出,后续只要多加一个特质,继承需要混入的特质

6.样例类

image-20240726110409580

  • 相当于实体类,但是出来默认是val,是不可变的

7.枚举类

  • 要继承Enumeration

  • object TableEnum extends Enumeration {
      type TableEnum = Value  // 把枚举类暴露出去
      val SCORE,STUDENT,TEACHER,COURSE=Value
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    ### 8.泛型类

    ![image-20240726110614451](https://pic1.sabthever.cn/Blog_Base_Resouces/bigdata/image-20240726110614451.png)

    - 例子

    压栈,输出新的List

    ```scala
    scala> val lst=List[Int]()
    lst: List[Int] = List()

    scala> 10 :: lst
    res0: List[Int] = List(10)

    scala> 20 :: (10 :: lst)
    res1: List[Int] = List(20, 10)

9.类型边界

  • 在Scala中,类型参数可以有一个类型边界约束
  • 类型上界:将类型限制为另一种类型的子类
    • T<:A 表示类型变量T应该是类型A的子类
    • A是具体类型,T是泛型
  • 类型下界:将类型声明为另一种类型的超类
    • T>:A 表示类型变量T应该是类型A的超类
    • A是具体类型,T是泛型

(九)进阶学习

1.Scala正则表达

  • 分割 匹配 替换 提取
A.初步
  • 一旦使用\就用"""regex""".r

  • image-20240726113531226

  • 例1 match提取方式

    1
    2
    3
    4
    5
    6
    val str = "1234566 1999-10-12T12:34:56 buy http://www.taobao.com/computer/1"
    val pattern = "([0-9]+) ([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}) ([a-z]+) .*".r
    str match {
    case pattern(userid,times,action)=>println(s"${userid},${times},${action}")
    }
    // 1234566,1999-10-12T12:34:56,buy
B.字符串匹配
  • image-20240726115042787
  • 例1

    1
    2
    3
    4
    5
    val str = "1234566 1999-10-12T12:34:56 buy http://www.taobao.com/computer/1 1999-10-12T12:34:56"
    val pattern = "[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}".r
    val matches = pattern.findAllMatchIn(str).toList
    println(matches)
    // List(1999-10-12T12:34:56, 1999-10-12T12:34:56)
  • findFirstMatchIn() 出Some和None

  • findAllMatchIn() 出Iterator

  • 例2 利用偏心函数对每一条获取值并输出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    val lst = List[String](
    "INFO 2017-12-29 requestURL:/c?abc=123&cde=456",
    "INFO 2017-12-30 requestURL:/c?abc=123&cde=789",
    "INFO 2017-12-30 requestURL:/c?abc=123&cde=346"
    )
    val pattern = """([A-Z]+) ([0-9]{4}-[0-9]{2}-[0-9]{2}) requestURL:(/.*)""".r

    lst.collect({
    case pattern(level,times,addr)=>(level,times,addr)
    }).foreach(println)
C.字符串替换

image-20240726115305237

2.

最后

  • 标题: 大数据学习笔记3-Scala
  • 作者: Sabthever
  • 创建于 : 2025-05-27 19:08:34
  • 更新于 : 2025-10-09 16:14:31
  • 链接: https://sabthever.cn/2025/05/27/technology/bigdata/Hadoop3-Scala/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。