第五次作业
1. 简述Scala语言的基本特性
1. 面向对象:Scala是一种完全面向对象的语言。其每一种数据类型都是一个对象,这使得它具有非常统一的模型。
2. 函数式编程:Scala同时支持函数式编程,它拥有高阶函数、闭包、不可变数据结构、递归等函数式编程的关键特性。
3. 扩展性:Scala的语法非常灵活,允许开发者自定义运算符和语法糖。也支持模式匹配、类型推断和匿名函数等高级特性,这些都为编写简洁、高效的代码提供了可能。此外,Scala的语法允许在单个文件中定义类、对象、函数等,使得代码组织更加灵活。
4. 并发性:Scala支持Actor模型(处理并发的轻量级机制)。通过Actor,可以编写出线程安全的、易于管理的并发代码,有效地利用多核处理器资源。
5. 可以和Java混编:Scala运行在Java虚拟机(JVM)上,并兼容Java的API。可以直接使用Java库,或者在Scala代码中调用Java方法,反之亦然。这为已有的Java项目提供了无缝迁移到Scala的可能,也使得Scala成为一个非常实用的工具,可以在不完全重构的情况下逐步引入新的编程范式。
2. 简述Scala语言的9种基本数据类型。 说明关键字Unit、Nothing、Any的含义。
Unit无返回值,通常用于不返回任何内容的方法。
Nothing是任何其他类型的子类,用于表示永远不会正常终止的程序部分。
Any是所有其他类型的超类(父类)
3. 简述Scala中数组、列表、集合、元组、映射的名称及特点。
数组(Array):固定大小的集合,元素类型相同,性能较好但不支持动态修改大小。
列表(List):不可变的序列集合,适合于递归处理和模式匹配,但头部插入和删除效率低。
集合(Set):无序且不重复元素的集合,分为可变和不可变两种。
元组(Tuple):固定长度、不同类型的元素组合,最多支持22个元素,常用于同时携带多种类型信息。
映射(Map):键值对的集合,键唯一,分为可变和不可变两种,适合快速查找。
4. 举例说明匿名函数和高阶函数的含义,
匿名函数
也称为Lambda函数。箭头“=>”定义,箭头的左边是参数列表,箭头的右边是表达式,表达式的值即匿名函数的返回值。 在代码中直接定义的函数,没有具体的函数名。通常用于一些简单的、一次性的操作。
val sum = (x: Int, y: Int) => x + y
val result = sum(3, 5) /
/ result = 8
高阶函数
高阶函数是指使用其他函数作为参数,或者返回一个函数作为结果的函数。
val numbers = List(1, 2, 3, 4)
val doubled = numbers.map(x => x * 2)
// doubled = List(2, 4, 6, 8)
5. 阅读、分析下列程序段,并给出运行结果。
(1)
var v = 0
for (i <- 1 to 9) {
for (j <- 1 to i) {
v = i*j
print(f"$j%s*$i%s=$v%-3s")
}
println()
}
(2)
val a = Array("Hello Spark","Hello Hadoop","Hello Scala")
val b = a.flatMap(_.split(" ")).map((_,1)).groupBy(t => t._1).map(t => (t._1,t._2.length)).toList.sortBy(t => t._2).reverse
b.foreach(x => println(x))
(3)
class Person(val namec:String,val agec:Int) {
var name:String = namec
var age:Int = agec
def printPerson() : Unit = {
printf(f"name:$name%8s, age:$age%-4d")
}
}
object Test2 {
def main(args:Array[String]):Unit = {
val x = new Person("zhang",21)
x.printPerson()
}
}
(4)
val a = List(("a",85),("b",95),("c",75),("a",95))
a.groupBy(_._1)
(5)
val s = List("Spark","Python","Hadoop","HBase")
s.foreach(e => print(e+" "))
print(s.count(e => e.length == 5))
(1) 打印九九乘法表
var v = 0
for (i <- 1 to 9) {
for (j <- 1 to i) {
v = i*j
print(f"$j%s*$i%s=$v%-3s") // 使用格式化字符串打印乘法公式
}
println() // 每行结束后换行
}
代码分析:
var v = 0
: 定义一个变量v
用于存储乘积结果,初始值为 0。for (i <- 1 to 9)
: 外层循环遍历 1 到 9 的数字,代表乘法表的行数。for (j <- 1 to i)
: 内层循环遍历 1 到当前行数i
的数字,代表乘法表的列数。v = i*j
: 计算当前行i
和当前列j
的乘积,并将结果存储在v
中。print(f"$j%s*$i%s=$v%-3s")
: 使用格式化字符串f""
打印乘法公式。$j%s
: 打印当前列数j
,并使用%s
保持字符串格式。*$i%s
: 打印乘号和当前行数i
,并使用%s
保持字符串格式。=$v%-3s
: 打印等号和乘积结果v
,并使用%-3s
将结果左对齐,宽度为 3 个字符。
println()
: 每行结束后换行,确保乘法表格式正确。
(2) 统计单词出现次数并排序
val a = Array("Hello Spark","Hello Hadoop","Hello Scala")
val b = a.flatMap(_.split(" ")).map((_,1)).groupBy(t => t._1).map(t => (t._1,t._2.length)).toList.sortBy(t => t._2).reverse
b.foreach(x => println(x))
代码分析:
val a = Array("Hello Spark","Hello Hadoop","Hello Scala")
: 定义一个包含三个字符串的数组a
。val b = a.flatMap(_.split(" ")).map((_,1)).groupBy(t => t._1).map(t => (t._1,t._2.length)).toList.sortBy(t => t._2).reverse
: 一系列操作,统计每个单词出现的次数,并按照次数降序排序。flatMap(_.split(" "))
: 将数组a
中的每个字符串按空格分割成单词,并将所有单词扁平化到一个新的数组中。map((_,1))
: 将每个单词转换为一个元组,第一个元素为单词本身,第二个元素为 1,表示该单词出现一次。groupBy(t => t._1)
: 按单词分组,将相同单词的元组放在一起。map(t => (t._1,t._2.length))
: 将每个分组转换为一个新的元组,第一个元素为单词,第二个元素为该单词出现的次数。toList
: 将结果转换为 List。sortBy(t => t._2)
: 按单词出现次数升序排序。reverse
: 将排序结果逆序,实现降序排序。
b.foreach(x => println(x))
: 遍历排序后的 Listb
,并打印每个元组,即单词和出现次数。
(3) 定义 Person 类并创建对象
class Person(val namec:String,val agec:Int) {
var name:String = namec
var age:Int = agec
def printPerson() : Unit = {
printf(f"name:$name%8s, age:$age%-4d")
}
}
object Test2 {
def main(args:Array[String]):Unit = {
val x = new Person("zhang",21)
x.printPerson()
}
}
代码分析:
class Person(val namec:String,val agec:Int)
: 定义一个名为Person
的类,包含两个参数namec
和agec
,分别代表姓名和年龄。val namec:String,val agec:Int
: 声明两个参数,并使用val
修饰,表示参数的值在对象创建后不可变。
var name:String = namec
: 定义一个名为name
的可变变量,用于存储姓名,并将其初始化为参数namec
的值。var age:Int = agec
: 定义一个名为age
的可变变量,用于存储年龄,并将其初始化为参数agec
的值。def printPerson() : Unit = { ... }
: 定义一个名为printPerson
的方法,用于打印 Person 对象的姓名和年龄。printf(f"name:$name%8s, age:$age%-4d")
: 使用格式化字符串f""
打印姓名和年龄。name:$name%8s
: 打印 "name:" 和 姓名,并使用%8s
将姓名右对齐,宽度为 8 个字符。age:$age%-4d
: 打印 "age:" 和 年龄,并使用%-4d
将年龄左对齐,宽度为 4 个字符。
object Test2
: 定义一个名为Test2
的对象,包含main
方法。def main(args:Array[String]):Unit = { ... }
: 定义main
方法,用于执行程序。val x = new Person("zhang",21)
: 创建一个名为x
的Person
对象,并传入姓名 "zhang" 和年龄 21 作为参数。x.printPerson()
: 调用x
对象的printPerson
方法,打印 Person 对象的姓名和年龄。
(4) 使用 groupBy 对 List 进行分组
val a = List(("a",85),("b",95),("c",75),("a",95))
a.groupBy(_._1)
代码分析:
val a = List(("a",85),("b",95),("c",75),("a",95))
: 定义一个包含四个元组的 Lista
。a.groupBy(_._1)
: 使用groupBy
方法对a
进行分组,按照每个元组的第一个元素进行分组。_._1
: 使用下划线_
表示匿名函数,并使用._1
提取每个元组的第一个元素。
(5) 遍历 List 并统计长度为 5 的元素个数
val s = List("Spark","Python","Hadoop","HBase")
s.foreach(e => print(e+" "))
print(s.count(e => e.length == 5))
代码分析:
val s = List("Spark","Python","Hadoop","HBase")
: 定义一个包含四个字符串的 Lists
。s.foreach(e => print(e+" "))
: 使用foreach
方法遍历s
中的每个元素,并打印每个元素后加一个空格。e => print(e+" ")
: 匿名函数,将每个元素e
打印出来,并在后面加一个空格。
print(s.count(e => e.length == 5))
: 使用count
方法统计s
中长度为 5 的元素个数,并打印结果。e => e.length == 5
: 匿名函数,判断每个元素e
的长度是否等于 5。