大数据学习-Scala

大数据学习-Scala

/**
 *  1、scala代码中可以使用java的类和方法
 *  2、scala代码中一行语句的结束是以换行符为标准,可以不用写分号
 *  3、class是一个普通的类,object相当于一个单例对象,object类中的方法相当于加上一个static关键字
 */
/**
     * 字符串拼接
     * 1、+拼接 这种方式特别消耗性能的
     * 2、StringBuilder或者StringBuffer
     * 3、利用scala中的方法进行拼接
     * 4、scala中也提供了一个类似拼接的方式语法 s"${xx}"
*/
 /**
   *  定义函数时的简写
   *  1、如果函数体中最后一行语句作为返回值的时候,return可以省略不写
   *  2、如果函数体中只有一行语句实现,那么大括号也可以不用编写
   *  3、函数的返回值可以进行自动类型推断,可以省略不写
   *  4、如果函数没有参数列表的话,()也可以省略不写,def add5 = println("好好学习,天天向上")
*/
 * scala是对java语言的封装,scala中的异常类实际上就是java中的异常
 * Error
 * Exception
 *    - 编译时期异常
 *    - 运行时期异常 RuntimeException

 * 面向对象编程思想:是将对象传来传去的
 * 1、将对象作为方法的参数进行传递
 * 2、将对象作为方法的返回值类型进行返回
 * 需要明确的是对象的类,抽象类或者接口的类型,可以使用多态进行传递或者返回
 *
 * 函数式编程思想:将函数传来传去
 * 1、将函数A作为函数B的参数进行传递  必须要熟练掌握的
 * 2、将函数A作为函数B的返回值类型    必须要能够看懂即可
 * 需要明确的是函数的类型 -- 主要是由参数列表和返回值类型决定的
 * 使用scala语法描述一个函数类型:
 * 举例:String => Int
 /**
     * 函数作为方法参数传递的时候,这里的参数函数可以使用lambda表达式改写
     * lambda表达式 -- 匿名函数 (没有名字的函数)
     * (s:String) => s.toInt
     *
     */
    val f1: String => Int = (s: String) => s.toInt + 22
    fun("11", f1)

    //函数只有一行的时候,传参可以直接传入一个匿名函数
    fun("22", (s: String) => s.toInt + 100)

    //lambda表达式的参数类型可以进行自动推断
    fun("22", s => s.toInt)

    //如果传入的函数参数有且仅只用了一次的话,可以直接使用_代替
    fun("22", _.toInt)

 /**
     *  当函数原本一次性传递多个参数的时候,现在改成分开传递参数的形式,增加了函数的灵活性和可复用性
     *  这样调用的方式有一个数学概念:柯里化
     *  scala的函数柯里化:函数的返回值依旧是一个函数,继续传参
     *
     *  面试题:请你说一说scala中的函数柯里化指的是什么?
 */



package com.shujia.jichu

import java.sql.{Connection, DriverManager, PreparedStatement, ResultSet}

object Demo20JDBC {
  def main(args: Array[String]): Unit = {
    /**
     *  scala中连接数据库
     */
    //加载驱动
    Class.forName("com.mysql.jdbc.Driver")

    //创建与数据库连接对象
    val conn: Connection = DriverManager.getConnection("jdbc:mysql://192.168.220.100/studentdb?useUnicode=true&characterEncoding=utf8&useSSL=false", "root", "123456")

    //为了防止sql注入
    val state: PreparedStatement = conn.prepareStatement("select id,name,age,gender,clazz from student where clazz=?")

    state.setString(1,"文科一班")

    //执行sql语句
    val resultSet: ResultSet = state.executeQuery()

    while (resultSet.next()){
      val id: Int = resultSet.getInt("id")
      val name: String = resultSet.getString("name")
      val age: Int = resultSet.getInt("age")
      val gender: String = resultSet.getString("gender")
      val clazz: String = resultSet.getString("clazz")
      println(s"学号:${id},姓名:${name},年龄:${age},性别:${gender},班级:${clazz}")
    }

    //释放资源
    state.close()
    conn.close()
  }

}
/**
     * 定义一个隐式转换方法:可以将参数类型转换成返回值类型
     *
     * 注:
     *  1、scala编译器,在编译代码的时候,会识别到需要将A类型转B类型,然后就去找参数是A类型,返回值是B类型的隐式转换函数,自动调用,否则找不到报错
     *  2、只针对参数类型和返回值类型,和隐式函数叫什么无关
     *  3、同一种参数和返回值类型组合的隐式转换函数,同一作用域下只能出现一种
*/

* 统计班级人数 [班级,人数]
* 统计学生的总分 [学号,学生姓名,学生年龄,总分]
* 1、统计年级排名前十学生各科的分数 [学号,  姓名,班级,科目,分数]
* 2、统计总分大于年级平均分的学生 [学号,姓名,班级,总分]
* 3、统计每科都及格的学生 [学号,姓名,班级,科目,分数]
* 4、统计每个班级的前三名 [学号,姓名,班级,分数]
* 5、统计偏科最严重的前100名学生  [学号,姓名,班级,科目,分数]

package com.shujia.zuoye

import scala.io.{BufferedSource, Source}


object HomeWork {
  //定义一些样例类,保存每一行的数据
  private case class Student(id: String, name: String, age: Int, gender: String, clazz: String)

  private case class Score(id: String, subject_id: String, score: Int)

  private case class Subject(subject_id: String, subject_name: String, subject_score: Int)

  //定义一些变量
  private var stuList: List[Student] = _
  private var scoreList: List[Score] = _
  private var subjectList: List[Subject] = _

  //定义一些Map变量,帮助后期的关联
  private var stuInfoMap: Map[String, String] = _
  private var subNameMap: Map[String, String] = _
  private var subScoreMap: Map[String, Int] = _

  private def loadData(): Unit = {
    //读取文件数据,将每一行封装成样例类到集合中
    val stuBS: BufferedSource = Source.fromFile("scala/data/students.csv")
    //处理读取到的学生数据,赋值给变量stuList
    stuList = stuBS.getLines()
      .toList // ["1500100978,郜昆卉,21,男,文科五班","xxx","xx"]
      .map((s: String) => {
        val strings: Array[String] = s.split(",")
        val id: String = strings(0)
        val name: String = strings(1)
        val age: Int = strings(2).toInt
        val gender: String = strings(3)
        val clazz: String = strings(4)
        //封装成一个Student类对象
        Student(id, name, age, gender, clazz)
      })
    //stuInfoMap
    //将学生的学号id作为键,姓名name和班级clazz作为value放入到Map集合中
    stuInfoMap = stuList.map((stu: Student) => (stu.id, stu.name + "," + stu.clazz)).toMap

    //读取文件数据,将每一行封装成样例类到集合中
    val scoreBS: BufferedSource = Source.fromFile("scala/data/score.txt")
    //处理读取到的学生数据,赋值给变量stuList
    scoreList = scoreBS.getLines()
      .toList // ["1500100978,郜昆卉,21,男,文科五班","xxx","xx"]
      .map((s: String) => {
        val strings: Array[String] = s.split(",")
        val id: String = strings(0)
        val subject_id: String = strings(1)
        val score: Int = strings(2).toInt
        //封装成一个Student类对象
        Score(id, subject_id, score)
      })


    //读取文件数据,将每一行封装成样例类到集合中
    val subjectBS: BufferedSource = Source.fromFile("scala/data/subject.csv")
    //处理读取到的学生数据,赋值给变量stuList
    subjectList = subjectBS.getLines()
      .toList // ["1500100978,郜昆卉,21,男,文科五班","xxx","xx"]
      .map((s: String) => {
        val strings: Array[String] = s.split(",")
        val subject_id: String = strings(0)
        val subject_name: String = strings(1)
        val subject_score: Int = strings(2).toInt
        //封装成一个Student类对象
        Subject(subject_id, subject_name, subject_score)
      })
    //使用科目编号subject_id作为键,科目的名字作为value值
    subNameMap = subjectList.map((subject: Subject) => (subject.subject_id, subject.subject_name)).toMap
    //使用科目编号subject_id作为键,科目总分单独作为value值
    subScoreMap = subjectList.map((subject: Subject) => (subject.subject_id, subject.subject_score)).toMap
  }

  //尝试将三个不同的数据进行关联 输出我们想要看的学生信息,传入的是我们想要看的学生编号组成的集合
  //学号,姓名,班级,科目,分数
  private def printResultWithId(ids: List[String]): Unit = {
    //基于分数表的数据,结合两个Map数据类型进行关联,利用了中间表的id关联
    scoreList.filter((s: Score) => ids.contains(s.id)) //过滤出函数传入的学生id集合
      .map((s: Score) => {
        //利用Score样例类中的id,在学生Map集合中找学生信息 name,clazz
        val nameWithClazz: String = stuInfoMap.getOrElse(s.id, "查无此人")
        //利用Score样例类中的subject_id,在科目名称Map集合中找科目名字信息 subject_name
        val subjectName: String = subNameMap.getOrElse(s.subject_id, "没有这个科目")
        s"${s.id},${nameWithClazz},${subjectName},${s.score}"
      }).foreach(println)
  }

  /**
   * 题目1:统计班级人数 [班级,人数]
   */
  private def clazzCount(): Unit = {
    stuList.groupBy((s: Student) => s.clazz) //根据班级进行分组
      .map((kv: (String, List[Student])) => kv._1 + "," + kv._2.size) //聚合
      .foreach(println)

//    val stringToStudents: Map[String, List[Student]] = stuList.groupBy((s: Student) => s.clazz)
  }

  /**
   * 题目2:统计学生的总分 [学号,学生姓名,学生年龄,总分]
   */
  private def studentSumScore(): Unit = {
    val studentSumScoreRes: Map[String, Int] = scoreList.groupBy((s: Score) => s.id) //根据学生的学号分组
      //(1500100112,List(Score(1500100112,1000001,33), Score(1500100112,1000002,7), Score(1500100112,1000003,136), Score(1500100112,1000007,62), Score(1500100112,1000008,49), Score(1500100112,1000009,72)))
      .map((kv: (String, List[Score])) => (kv._1, kv._2.map((s: Score) => s.score).sum))

    //与学生信息集合关联,根据学号id进行关联
    val stuSumScoreList: List[String] = stuList.map((s: Student) => {
      val sumScore: Int = studentSumScoreRes.getOrElse(s.id, 0)
      s"${s.id},${s.name},${s.age},$sumScore"
    })
    stuSumScoreList.foreach(println)
  }

  /**
   * 题目3:统计年级排名前十学生各科的分数 [学号,  姓名,班级,科目,分数]
   */
  private def studentSumScoreTop10(): Unit = {
    val ids: List[String] = scoreList.groupBy((s: Score) => s.id) //根据学号进行分组
      .map((kv: (String, List[Score])) => (kv._1, kv._2.map((s: Score) => s.score).sum))
      .toList
      .sortBy((kv: (String, Int)) => -kv._2)
      .take(10)
      .map((kv: (String, Int)) => kv._1)
    printResultWithId(ids)
  }

  /**
   * 题目4:统计总分大于年级平均分的学生 [学号,姓名,班级,总分]
   */
  private def sumScoreGAvgScore(): Unit = {
    //先求出年级总平均分 372.0
    val avgSumScore: Double = (scoreList.map(_.score).sum / stuList.size).toDouble

    //统计每个学生的总分
    scoreList.groupBy((s: Score) => s.id) //根据学号进行分组
      .map((kv: (String, List[Score])) => (kv._1, kv._2.map((s: Score) => s.score).sum))
      .filter((kv: (String, Int)) => kv._2 > avgSumScore) //过滤出总分大于年级平均分的
      .map((kv: (String, Int)) => {
        //通过学号与学生数据进行关联
        val nameWithClazz: String = stuInfoMap.getOrElse(kv._1, "查无此人")
        s"${kv._1},$nameWithClazz,${kv._2}"
      }).foreach(println)
  }

  /**
   * 题目5:统计每科都及格的学生 [学号,姓名,班级,科目,分数]
   * 一般来说是总分的60%
   */
  private def subjectPassStudents(): Unit = {
    //通过每一个Score中的科目编号拿到对应的科目总分
    val ids: List[String] = scoreList.filter((s: Score) => s.score >= subScoreMap.getOrElse(s.subject_id, 0) * 0.6)
      //统计每个学生及格的科目数
      .groupBy((s: Score) => s.id)
      .map((kv: (String, List[Score])) => (kv._1, kv._2.size))
      .filter((kv: (String, Int)) => kv._2 == 6)
      .keys //获取每门科目都及格的学生学号
      .toList

    printResultWithId(ids)
  }

  /**
   * 题目6:统计每个班级的前三名 [学号,姓名,班级,分数]
   */
  private def clazzSumScoreTop3(): Unit = {
    scoreList.groupBy((s: Score) => s.id) //根据学号进行分组
      .map((kv: (String, List[Score])) => (kv._1, kv._2.map((s: Score) => s.score).sum))
      //通过学号从学生的信息集合中将姓名和班级拿出来stuInfoMap
      .map((kv: (String, Int)) => {
        val nameWithClazz: String = stuInfoMap.getOrElse(kv._1, "查无此人")
        val strings: Array[String] = nameWithClazz.split(",")
        val name: String = strings(0)
        val clazz: String = strings(1)
        (kv._1, name, clazz, kv._2)
      })
      .groupBy(_._3) //根据班级进行分组
      .flatMap((kv: (String, Iterable[(String, String, String, Int)])) => {
        kv._2.toList.sortBy(-_._4).take(3)
      }).foreach(println)
  }

  /**
   * 题目7:统计偏科最严重的前100名学生  [学号,姓名,班级,科目,分数] 方差
   *
   * 每一个人的分数减去自己的平均分的总和除以科目数
   * 1500100001,1000001,98
   * 1500100001,1000002,5
   * 1500100001,1000003,137
   * 1500100001,1000004,29
   * 1500100001,1000005,85
   * 1500100001,1000006,52
   */
  private def partialBadlyStuTop100(): Unit = {
    //数据归一化,将数据处理到一个可控的范围中 0-100之间
    val ids: List[String] = scoreList.map((s: Score) => {
        (s.id, s.subject_id, s.score * 100.toDouble / subScoreMap.getOrElse(s.subject_id, 0))
      }).groupBy(_._1)
      .map((kv: (String, List[(String, String, Double)])) => {
        val id: String = kv._1 // 学号
        val scoreGuiList: List[(String, String, Double)] = kv._2
        //计算个人的平均分
        val stuGeRenAvgScore: Double = scoreGuiList.map(_._3).sum / scoreGuiList.size
        //计算方差
        val partial: Double = scoreGuiList.map((t: (String, String, Double)) => {
          Math.pow(t._3 - stuGeRenAvgScore, 2)
        }).sum / scoreGuiList.size
        (id, partial)
      }).toList
      .sortBy(-_._2)
      .take(100)
      .map(_._1)

    printResultWithId(ids)
  }


  def main(args: Array[String]): Unit = {
    loadData()

    //    /**
    //     * 1500100985,申飞珍,21,女,文科一班
    //     * 1500100986,左天曼,22,女,文科一班
    //     * 1500100987,双昆杰,24,男,文科四班
    //     * 1500100988,余鸿云,22,男,文科六班
    //     */
    //    val ids: List[String] = List("1500100985", "1500100986", "1500100987", "1500100988")
    //    printResultWithId(ids)
    //    clazzCount() //题目1
    //    studentSumScore() //题目2
    //    studentSumScoreTop10() //题目3
    //    sumScoreGAvgScore() //题目4
    //    subjectPassStudents() //题目5
    //    clazzSumScoreTop3() //题目6
    partialBadlyStuTop100() //题目7

  }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值