头歌实践教学平台:Spark大数据编程(二十一~二十五)

二十一、九九乘法口诀表 - Scala

实训目标
掌握 for 循环的使用
了解 for 循环嵌套 for 循环用法
实训分析
九九乘法表一共有九行,每行等式的变量和行号相等,例如第二行包含两个等式,第六行包含 6 个等式,以此类推,第九行包含 9 个等式。根据其特点可知可使用for循环嵌套解决此问题。
我们可以定义变量i控制乘法表的行数与变量j控制乘法表等式量的输出。
第一个for循环用来控制乘法表中每行的第一个因子和表的行数;第二个for循环中变量j取值范围的确定建立在第一个for循环的基础上,它的取值是第一个for循环中变量的值,换言之,j的取值根据行数变化,运行到第几行,j的最大值就是几。
为了控制格式,将乘法表分行,需要在每行的末尾输出一个换行。

object Test {
  def main(args: Array[String]): Unit = {
    /********** Begin **********/
    // 外层循环控制行数(i 从 1 到 9)
    for (i <- 1 to 9) {
      // 内层循环控制每行的列数(j 从 1 到当前行数 i)
      for (j <- 1 to i) {
        // 打印乘法表达式,使用两个空格分隔
        print(s"$j*$i=${j*i}  ")
      }
      // 每行结束后换行
      println()
    }
    /********** End **********/
  }
}

二十二、商品价格区间设置与排序 - scala

实训目标
掌握 Scala 中的 ListBuffer
掌握列表的排序,能分别采用降序和升序两种方式排列列表元素
掌握列表的遍历

实训分析
本实训的目的是从10个商品价格中选出位于价格区间的部分商品价格,进行排序并输出,这个过程可拆分为两步:
(1)按用户设置的价格区间选择部分商品价格。根据用户输入的最大价格和最小价格确定价格区间,依次取出10个商品价格进行比较:若某商品价格位于此区间中,则将其进行保存。待所有的商品价格均做完比较后,此时得到位于价格区间内的部分商品价格。
(2)按用户选择的排序方式排列商品价格。根据用户输入的排序方式,将上一步骤中得到的部分商品价格重新排列。
由于上述过程中涉及到遍历、排序、动态存储等操作,这里使用列表来存储商品价格。

import scala.io.StdIn
import scala.collection.mutable.ListBuffer

object Test {
  def main(args: Array[String]): Unit = {
    val price = ListBuffer(399, 4369, 539, 288, 109, 749, 235, 190, 99, 1000)
    var section_li: ListBuffer[Int] = new ListBuffer[Int]()
    
    print("请输入最大价格:")
    val section_max = StdIn.readInt()
    println(section_max)
    
    print("请输入最小价格:")
    val section_min = StdIn.readInt()
    println(section_min)

    /********** Begin **********/
    // 遍历所有价格,筛选出在[section_min, section_max]区间内的价格(包含边界)
    for (p <- price) {
      if (p >= section_min && p <= section_max) {
        section_li += p  // 符合条件的价格添加到结果列表
      }
    }
    /********** End **********/

    // 排序选项分行显示(匹配预期输出格式)
    println("1.价格降序排序")
    println("2.价格升序排序")
    print("请选择排序方式:")  // 选择提示单独一行
    val choice_num = StdIn.readInt()
    println(choice_num)  // 回显用户选择

    /********** Begin **********/
    // 根据用户选择排序并输出结果
    choice_num match {
      case 1 =>  // 降序排序:sorted默认升序,reverse转为降序
        println(section_li.sorted.reverse)
      case 2 =>  // 升序排序:直接使用sorted方法
        println(section_li.sorted)
      case _ =>  // 输入无效时提示错误
        println("你输入的有误!!")
    }
    /********** End **********/
  }
}

二十三、词频统计 - scala

实训目标
掌握 Scala 的使用;

了解 Scala 下的 io 类,使用 io 类读取文件;

对文件中的单词进行拆分,并统计各单词的个数;

把统计好的单词数量进行从高到低进行排序。

实训分析
我们可以使用 Scala 中的io 类读取 df.txt 文件,再对df.txt 文件的英语句子进行拆分,分别统计出其中英文单词的个数,并对单词数量进行从高到低进行排序。

import scala.collection.immutable.ListMap
import scala.io.Source

object Test {
  def main(args: Array[String]): Unit = {
    /********** Begin **********/
    // 1. 读取文件内容,按行读取后合并为字符串(避免换行符残留)
    val fileLines = Source.fromFile("/data/bigfiles/df.txt").getLines()
    val fileContent = fileLines.mkString(" ")  // 每行用空格连接,消除换行符
    
    // 2. 拆分单词:用正则匹配纯英文单词(仅字母),忽略非字母字符
    val wordPattern = """[a-zA-Z]+""".r  // 匹配一个或多个字母的单词
    val words = wordPattern.findAllIn(fileContent).toList  // 提取所有匹配的单词
    
    // 3. 统计词频:分组后统计长度
    val wordCount = words.groupBy(identity).mapValues(_.length)
    
    // 4. 按词频降序排序,词频相同的顺序不影响(符合预期)
    val sortedWordCount = ListMap(wordCount.toSeq.sortWith((a, b) => a._2 > b._2): _*)
    
    // 5. 按指定格式输出
    sortedWordCount.foreach { case (word, count) =>
      println(s"($word,$count)")
    }
    /********** End **********/
  }
}

二十四、scala章节测验

第1关:第一题

任务描述
本关任务:根据编程要求,完成任务。

编程要求
打开右侧代码文件窗口,在 Begin 至 End 区域补充代码,完成任务。

请用脚本的方式编程计算并输出下列级数的前 n 项之和 Sn,直到 Sn 刚好大于或等于 q 为止,其中 q 为大于 0 的整数,其值通过 args(0) 获取(注意将其转换为数值型)。

例如,若 q 的值为 50.0,则输出应为:Sn=50.416695。

测试样例:

q=1 时,Sn=2;

q=30 时,Sn=30.891459;

q=50 时,Sn=50.416695。

object Test {
    def main(args: Array[String]) {
/*************** Begin ***************/

        // 定义初始的 Sn 和 n
        var Sn: Float = 0
        var n: Float = 1

        // 从 args 参数中获取 q 的值
        val q = args(0).toInt

        // 循环遍历计算
        while (Sn < q) {
            Sn += (n + 1) / n
            n += 1
        }

        // 输出计算结果
        println(s"当 q=$q 时,Sn=$Sn")

/*************** End ***************/
    }
}

第2关:第二题

任务描述
本关任务:根据编程要求,完成任务。

编程要求

对于一个图形绘制程序,用下面的层次对各种实体进行抽象。定义一个 Drawable 的特质,其包括一个 draw 方法,默认实现为输出对象的字符串表示。定义一个 Point 类表示点,其混入了 Drawable 特质,并包含一个 shift 方法,用于移动点。

所有图形实体的抽象类为 Shape,其构造函数包括一个 Point 类型,表示图形的具体位置(具体意义对不同的具体图形不一样)。Shape 类有一个具体方法 moveTo 和一个抽象方法 zoom,其中 moveTo 将图形从当前位置移动到新的位置,各种具体图形的 moveTo 可能会有不一样的地方。zoom 方法实现对图形的放缩,接受一个浮点型的放缩倍数参数,不同具体图形放缩实现不一样。

继承 Shape 类的具体图形类型包括直线类 Line 和圆类 Circle。Line 类的第一个参数表示其位置,第二个参数表示另一个端点,Line 放缩的时候,其中点位置不变,长度按倍数放缩(注意,缩放时,其两个端点信息也改变了),另外,Line 的 move 行为影响了另一个端点,需要对 move 方法进行重载。Circle 类第一个参数表示其圆心,也是其位置,另一个参数表示其半径,Circle 缩放的时候,位置参数不变,半径按倍数缩放。另外直线类 Line 和圆类 Circle 都混入了 Drawable 特质,要求对 draw 进行重载实现,其中类 Line 的 draw 输出的信息样式为“Line:第一个端点的坐标--第二个端点的坐标)”,类 Circle 的 draw 输出的信息样式为“Circle center:圆心坐标,R=半径”。

在右侧代码文件窗口中已经给出了 Drawable 和 Point 的定义,同时也给出了程序入口 main 函数的实现,请完成 Shape 类、Line 类和 Circle 类的定义。

case class Point(var x:Double,var y:Double) extends Drawable{
    def shift(deltaX:Double,deltaY:Double){x+=deltaX;y+=deltaY}
}
trait Drawable{
    def draw(){println(this.toString)}
}

/*************** Begin ***************/

// 请完成 Shape类、Line类和Circle类的定义。

// Shape 抽象类
abstract class Shape(val location: Point) {
  // 将图形移动到新位置
  def moveTo(newLocation: Point): Unit = {
    location.x = newLocation.x
    location.y = newLocation.y
  }
  
  // 缩放图形的抽象方法
  def zoom(scale: Double): Unit
}

// Line 类
class Line(val p1: Point, val p2: Point) extends Shape(p1) with Drawable {
  // 重写 moveTo 方法,移动时两个端点都要移动相同的距离
  override def moveTo(newLocation: Point): Unit = {
    val deltaX = newLocation.x - p1.x
    val deltaY = newLocation.y - p1.y
    
    p1.x = newLocation.x
    p1.y = newLocation.y
    p2.x += deltaX
    p2.y += deltaY
  }
  
  // 实现 zoom 方法:中点不变,长度按比例缩放
  override def zoom(scale: Double): Unit = {
    // 计算中点
    val centerX = (p1.x + p2.x) / 2
    val centerY = (p1.y + p2.y) / 2
    
    // 将端点相对于中点缩放
    p1.x = centerX + (p1.x - centerX) * scale
    p1.y = centerY + (p1.y - centerY) * scale
    p2.x = centerX + (p2.x - centerX) * scale
    p2.y = centerY + (p2.y - centerY) * scale
  }
  
  // 重写 draw 方法
  override def draw(): Unit = {
    println(s"Line:(${p1.x},${p1.y})--(${p2.x},${p2.y})")
  }
  
  override def toString: String = s"Line:(${p1.x},${p1.y})--(${p2.x},${p2.y})"
}

// Circle 类
class Circle(center: Point, var radius: Double) extends Shape(center) with Drawable {
  // 实现 zoom 方法:圆心不变,半径按比例缩放
  override def zoom(scale: Double): Unit = {
    radius *= scale
  }
  
  // 重写 draw 方法
  override def draw(): Unit = {
    println(s"Circle center:(${location.x},${location.y}),R=$radius")
  }
  
  override def toString: String = s"Circle center:(${location.x},${location.y}),R=$radius"
}

/*************** End ***************/

object MyDraw{
    def main(args: Array[String]) {
        val p=new Point(10,30)
        p.draw;
        val line1 = new Line(Point(0,0),Point(20,20))
        line1.draw
        line1.moveTo(Point(5,5))
        line1.draw
        line1.zoom(2)
        line1.draw
        val cir= new Circle(Point(10,10),5)
        cir.draw
        cir.moveTo(Point(30,20))
        cir.draw
        cir.zoom(0.5)
        cir.draw
    }
}

第3关:第三题

任务描述
本关任务:根据编程要求,完成任务。

编程要求
在 Begin 至 End 区域补充代码,按要求统计学生成绩,完成任务。

读取学生的成绩清单文件(路径:/data/bigfiles/student_transcript.txt),其格式如下所示,第一行为表头,各字段意思分别为学号、性别、课程名一、课程名二等,后面每一行代表一个学生的信息,各字段之间用空白符隔开。

object scoreReport {
    def main(args: Array[String]) {
/*************** Begin ***************/
        // 1. 读取成绩单文件(跳过表头,按空白符分割,提取有效字段)
        val lines = scala.io.Source.fromFile("/data/bigfiles/student_transcript.txt").getLines()
        val header = lines.next() // 跳过第一行表头
        // 解析每行数据:(性别, 数学成绩, 英语成绩, 物理成绩),成绩转为Double类型
        val scoreData = lines.map { line =>
            val parts = line.split("\\s+").filter(_.nonEmpty) // 按任意空白符分割,过滤空字符串
            val gender = parts(1)
            val math = parts(2).toDouble
            val english = parts(3).toDouble
            val physics = parts(4).toDouble
            (gender, math, english, physics)
        }.toList // 转为List便于后续处理

        // 2. 定义统计函数:输入成绩列表,返回(平均分, 最低分, 最高分),保留两位小数
        def calculateStats(scores: List[Double]): (Double, Double, Double) = {
            val avg = scores.sum / scores.size
            val min = scores.min
            val max = scores.max
            // 四舍五入保留两位小数
            (math.round(avg * 100) / 100.0, 
             math.round(min * 100) / 100.0, 
             math.round(max * 100) / 100.0)
        }

        // 3. 提取各门课程的全体成绩列表
        val allMath = scoreData.map(_._2)
        val allEnglish = scoreData.map(_._3)
        val allPhysics = scoreData.map(_._4)

        // 4. 统计全体学生并输出结果
        println("course\taverage\tmin\tmax")
        val (mathAvg, mathMin, mathMax) = calculateStats(allMath)
        println(f"Math:\t$mathAvg%.2f\t$mathMin%.2f\t$mathMax%.2f")
        val (engAvg, engMin, engMax) = calculateStats(allEnglish)
        println(f"English:\t$engAvg%.2f\t$engMin%.2f\t$engMax%.2f")
        val (phyAvg, phyMin, phyMax) = calculateStats(allPhysics)
        println(f"Physics:\t$phyAvg%.2f\t$phyMin%.2f\t$phyMax%.2f")

        // 5. 按性别分组,提取男生/女生的各门课程成绩
        val maleData = scoreData.filter(_._1 == "male")
        val femaleData = scoreData.filter(_._1 == "female")

        val maleMath = maleData.map(_._2)
        val maleEnglish = maleData.map(_._3)
        val malePhysics = maleData.map(_._4)

        val femaleMath = femaleData.map(_._2)
        val femaleEnglish = femaleData.map(_._3)
        val femalePhysics = femaleData.map(_._4)

        // 6. 统计男学生数据并输出结果
        println("course\taverage\tmin\tmax (males)")
        val (maleMathAvg, maleMathMin, maleMathMax) = calculateStats(maleMath)
        println(f"Math:\t$maleMathAvg%.2f\t$maleMathMin%.2f\t$maleMathMax%.2f")
        val (maleEngAvg, maleEngMin, maleEngMax) = calculateStats(maleEnglish)
        println(f"English:\t$maleEngAvg%.2f\t$maleEngMin%.2f\t$maleEngMax%.2f")
        val (malePhyAvg, malePhyMin, malePhyMax) = calculateStats(malePhysics)
        println(f"Physics:\t$malePhyAvg%.2f\t$malePhyMin%.2f\t$malePhyMax%.2f")

        // 7. 统计女学生数据并输出结果
        println("course\taverage\tmin\tmax (females)")
        val (femaleMathAvg, femaleMathMin, femaleMathMax) = calculateStats(femaleMath)
        println(f"Math:\t$femaleMathAvg%.2f\t$femaleMathMin%.2f\t$femaleMathMax%.2f")
        val (femaleEngAvg, femaleEngMin, femaleEngMax) = calculateStats(femaleEnglish)
        println(f"English:\t$femaleEngAvg%.2f\t$femaleEngMin%.2f\t$femaleEngMax%.2f")
        val (femalePhyAvg, femalePhyMin, femalePhyMax) = calculateStats(femalePhysics)
        println(f"Physics:\t$femalePhyAvg%.2f\t$femalePhyMin%.2f\t$femalePhyMax%.2f")
/*************** End ***************/
    }
}

二十五、Spark 的部署与应用方式

任务描述
本关任务:根据相关知识内容完成右侧习题。

有任何问题都可以随时关注私信!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值