Scala课程习题解答
1.基础
(1)用体重和身高计算BMI值,它需要满足下面的测试:
(体重(公斤) / 身高2(cm2)
例如:一個52公斤的人,身高是155厘米,則BMI为:52(公斤)/1.552 (cm2 )= 21.6)小于18.5 体重过轻, 18.5~24 正常 大于 24 过重.
val normal = bmiStatus(75, 183)
Assert(“Normal weight”== normal,”Expected Normal Weight, Got”+ normal)
val normal = bmiStatus(160, 68)
Assert(“Normal weight”== normal,”Expected Normal Weight, Got”+ normal)
val normal = bmiStatus(160, 68)
Assert(“Normal weight”== normal,”Expected Normal Weight, Got”+ normal)
代码
class BMI {
def bmiStatus(weight:Double,height:Double):String={
val bmi=weight/((height/100)*(height/100));
bmi match{
case bmi if(bmi>24)=>"Over Weight"
case bmi if(bmi<18.5)=>"Below Weight"
case _ =>"Normal weight"
}
}
}
object test{
def main(args: Array[String]): Unit = {
val bmi=new BMI
val normal = bmi.bmiStatus(75, 183)
println(normal)
assert("Normal weight"== normal,"Expected Normal Weight, Got"+ normal)
val normal2 = bmi.bmiStatus(68, 170)
println(normal2)
assert("Normal weight"== normal2,"Expected Normal Weight, Got"+ normal2)
val normal3 = bmi.bmiStatus(58, 160)
println(normal3)
assert("Normal weight"== normal3,"Expected Normal Weight, Got"+ normal3)
}
}
(2)彩票小程序,编写 Scala 小程序Lottery,设计自己的函数实现以下功能:
1 允许用户输入7个 1~35 的数字(用户购买彩票,程序能检测出非法数值,提示重新输入)
2 随机生成7个数字(开奖),系统自动兑奖并返回中奖结果
代码
class Lottery {
val res = new Array[Int](7)
var nums = new Array[Int](7)
def input():Unit = {
try {
for (i <- 0 to 6) {
println("please input a num in [1,35]")
nums(i) = scala.io.StdIn.readInt();
while (nums(i) < 1 || nums(i) > 35) {
println("invalid num,please input a num in [1,35]")
nums(i) = scala.io.StdIn.readInt();
}
}
}
catch {
case Throwable=>{
println("invalid num,please input a num in [1,35]")
input()
}
}
}
def generate() = {
res.map(_ => scala.util.Random.nextInt(36))
}
def calculate(): String = {
var sum = 0;
for (i <- 0 until 7) {
val result = res(i)
val num = nums(i)
println(s"result:$result your input $num")
if (nums(i) == res(i)) {
sum += 1;
}
}
sum match {
case 0 => "sorry"
case 1 => "not bad"
case 2 => "just so so"
case 3 => "good"
case 4 => "great"
case 5 => "very good"
case 6 => "excellent"
case 7 => "unbelievable"
}
}
}
object Lottery {
def main(args: Array[String]): Unit = {
val lottery = new Lottery();
lottery.input();
lottery.generate();
print(lottery.calculate());
}
}
2.面向对象
1.编写一个Time类,加入只读属性hours和minutes,和一个检查某一时刻是否早于另一时刻 的方法before(other:Time):Boolean。Time对象应该以new Time(hrs,min)方式构建。其中hrs以 军用时间格式呈现(介于0和23之间)
代码
class Time(val hrs: Int, val mins: Int) {
if (hrs > 24 || hrs < 0 || mins > 60 || mins < 0) {
throw new Exception("invalid hours or minutes,construct failed")//暂时没有找到怎么在构造函数中限制参数的范围
}
def before(other: Time): Boolean = {
if (this.hrs < other.hrs) {
true
}
else if (this.hrs == other.hrs) {
if (this.mins < this.mins) {
true
}
false
}
else {
false
}
}
}
object Time{
def main(args: Array[String]): Unit = {
val time=new Time(24,12);
val time1=new Time(22,12);
println(time1.before(time))
val time2=new Time(121,12)
}
}
2.定义抽象类Animal,在抽象类中定义抽象方法animal 和 sound,并定义templateMethod 方法,在这个方法中直接调用animal 和sound方法是否合理?
代码
abstract class Animal {
abstract def animal(): String
abstract def sound(): String
abstract def food(): String
def templateMethod(): Unit = {
animal();
sound();
}
}
class Duck extends Animal {
override def animal(): String = "duck"
override def sound(): String = "ga ga"
override def food(): String = "plants"
}
class Cow extends Animal{
override def animal(): String = "cow"
override def sound(): String ="mou mou"
override def food(): String = "grass"
}
object Animal {
def main(args: Array[String]): Unit = {
val duck =new Duck
println(duck.food())
assert("plants"== duck.food(),"Expected plants, Got"+ duck.food())
val cow=new Cow
println(cow.food())
assert("grass"==cow.food(),"Expected Normal Weight, Got"+ cow.food())
}
}
定义两种实现类,实现Animal,修 改Animal 和它的子类,使其还能表示动物都吃什么。所编写的代码需要满足如下测试
val duck = new Duck
Duck food is “plants”
val cow = new Cow
Cow.food is “grass”
3.自己设计一套特质,要求体现叠加在一起的特质,设计具体的抽象方法抽象字段
创建trait BatteryPower 来报告剩余电量。如果电量多余40%,那么报告“green”;如果在 20%~39% 之间 那么报告yellow;如果少于20%,那么报告”red”。实例化该代码满足下列测试:
class Battery extends EnergySource with BatteryPower
val battery = new Battery
battery.monitor(80) is “green”
battery.monitor(30) is “yellow”
battery.monitor(10) is “red”
代码
trait Power {
def cal(power: Double): Double = {
power
}
}
trait EnergySoure extends Power {
override def cal(power: Double): Double = {
power
}
}
trait BatteryPower extends Power {
override def cal(power: Double): Double = {
power match {
case power if (super.cal(power) >= 40) => 2.0
case power if (super.cal(power) < 20) => 0.0
case _ => 1.0
}
}
}
class Battery extends EnergySoure with BatteryPower {
def monitor(power: Double): String = {
super.cal(power) match {
case 0.0 => "red"
case 1.0 => "yellow"
case 2.0 => "green"
}
}
}
object Battery {
def main(args: Array[String]): Unit = {
val battery = new Battery
val green = battery.monitor(44)
println(green)
assert("green" == green, "Expected green, Got" + green)
val yellow = battery.monitor(24)
println(yellow)
assert("yellow" == yellow, "Expected yellow, Got" + yellow)
val red = battery.monitor(4)
println(red)
assert("red" == red, "Expected red, Got" + red)
}
}
曲线救国,其实我也没着真正理解特质叠加的精髓,只能依葫芦画瓢。
4.通过把 scala.math.Ordered[Point] 混入 java.awt.Point 的方式,定义 OrderedPoint 类, 按照词典的编辑方式排序,也就是说,如果x <x`或者x=x’或者y<y’则(x,y)<(x’,y’)
代码
import java.awt.Point
import scala.math.Ordered;
class OrderedPoint(x:Int,y:Int) extends Point(x:Int,y:Int) with Ordered[Point] {
override def compare(that: Point): Int = {
//直接重写了Ordered的compare方法
if (this.x < that.x || this.x == that.x || this.y < that.y) {
0
}
1
}
}
object OrderedPoint{
def main(args: Array[String]): Unit = {
val orderedPoint1=new OrderedPoint(1,2)
val orderedPoint2=new OrderedPoint(2,23)
print(orderedPoint1.compare(orderedPoint2))
}
}
5.尝试设计一套特质,灵活的改动整数队列。队列有两种操作:put把整数放入队列,get从尾 部取出它们。队列是先进先出的,get应该依照入队列的顺序取数据。
提示:可以用mutable.ArrayBuffer 模拟队列
在报告中体现出类的线性化特性,要求扩展类实现如下三个功能
- Doubling 把放到队列中的数字翻倍
- Incrementing 把放到队列的数据增加1
- 过滤掉队列中的负数
代码
package zun
import scala.collection.mutable.ArrayBuffer
abstract class Queue {
println("queue cons")
var arrayBuffer = new ArrayBuffer[Int]()
def put(num: Int): Unit
def get(): Int = {
arrayBuffer.remove(0)
}
def show()={
arrayBuffer.foreach(println)
}
}
trait Doubling extends Queue {
println("double cons")
abstract override def put(num: Int): Unit = {
println("double put")
super.put(2 * num)
}
}
trait Incrementing extends Queue {
println("incre cons")
abstract override def put(num: Int): Unit = {
println("incre put")
super.put(num + 1)
}
}
trait NegativeFiltering extends Queue {
println("nega cons")
abstract override def put(num: Int): Unit = {
println("nega put")
if (num > 0) {
super.put(num)
}
else {
println("please append positive")
}
}
}
class NewQueue extends Queue {
override def put(num: Int): Unit = {
arrayBuffer += num
}
}
object Queue {
def main(args: Array[String]): Unit = {
//体现线性化顺序
val queue = new NewQueue() with Doubling with Incrementing with NegativeFiltering
queue.put(1)
queue.put(2)
queue.put(-1)
queue.put(22)
queue.show()
}
}
有个疑问 ,在实例化时with和类中with有什么不同?
3.函数
1.下面程序改成高阶程序
代码
object MyModule {
private def formatAbs(func: (Int) => Int, x: Int) ={
val msg = "the absolute value of %d is %d"
msg.format(x, func(x))
}
def main(args: Array[String]): Unit = {
println(formatAbs(x=> if (x >= 0) x else -x, -23))
}
}
2.用correspond方法让我们判断某个字符串数组里面所有元素的长度是否和某个给定的整数数组一致。
代码
一一对应
object TestCorrespond {
def main(args: Array[String]): Unit = {
val a=Array("aa","bb","cc","dd")
val b=Array(2,2,2,2)
val c=Array(1,2,3)
val d=Array(1,2,3,4)
println(a.corresponds(b)(_.length==_))
println(a.corresponds(c)(_.length==_))
println(a.corresponds(d)(_.length==_))
}
}
3.假设某国的货币有若干面值,现给一张大面值的货币要兑换成零钱,问有多少种兑换方式。 用尾递归实现。
代码
def countChange(money: Int, coins: List[Int]): Int = {
if (money == 0) 1
else if (coins.size == 0 || money < 0) 0
else countChange(money, coins.tail) + countChange(money - coins.head, coins)//不使用当前的零钱+使用当前的零钱
}
def main(args: Array[String]): Unit = {
val coins = List(1, 5, 10, 20, 50, 100);
coins.foreach(println)
val money = 53;
println(countChange(money, coins))
println(ans)
}
4.写一个递归函数,来获取第n个斐波那契数,前两个斐波那契数0 和 1,第n个数总是等于前 两个数的和——序列开始为0,1,1,2,3,5.请定义尾递归函数 def fib(n: Int): Int
代码
object FIb {
def fib(n:Int):Int={
def cal(n:Int,before:Int,after:Int):Int={
if(n==1) before
else cal(n-1,after,before+after)
}
cal(n,0,1)
}
def main(args: Array[String]): Unit = {
println(fib(6))
}
}
5.定义一个操作符+%,将一个给定的百分比添加到某个值。举例来说120 +% 10 = 132,由于操 作符是方法而不是函数,你需要提供一个implicit。
代码
package zun
class AddPercent(x: Double) {
def +%(n: Double)= x + x * n * 0.01
}
object Operator {
implicit def test(x: Double) = new AddPercent(x)//这个函数名可以是任意的
def main(args: Array[String]): Unit = {
println(120.+%(10))
}
}
4.集合操作
1.一千万个随机数,随机数范围在1到1亿之间,现在要求写出一种算法,将1到1亿之间没有出现的随机数求出来。
代码
def main(args: Array[String]): Unit = {
val bat = BitSet() ++ (1 to 10000000).par.toList
val bit = BitSet() ++ (1 to 100000000).par.map(x => Random.nextInt(10000000) + 1).toList
val res = bat -- bit
println(res)
println(bat)
println(bit)
println(res.size)
}
2. 编 写 一 个 函 数 , 接 收 一 个 字 符 串 集 合 , 以 及 一 个 从 字 符 串 到 整 数 的 映 射 ,返回整数集合,其值为能和集合中某个字符串相应的映射值。举例来说,给定Array(“Tom”,“Fred”,“Harry”) 和 Map(“Tom”->3,“Dick”->4,“Harry”->5),返回Array(3,5)
代码
object Mapper {
def mapper(names:Array[String],map:Map[String,Int]):Array[Int]={
names.flatMap(map.get(_))//相当于将结果扁平化了
}
def main(args: Array[String]): Unit = {
val names=Array("Tom","Fred","Harry")
val map=Map("Tom"->3,"Dick"->4,"Harry"->5)
println(mapper(names,map).mkString(","))
}
}
3.对给定的整型列表lst,(lst :\ ListInt)(:: )得到的是什么? (ListInt /: lst)(:+)又得到什么?如何修改这两个操 作,对原来列表反向操作?
代码
object ListOperation {
def main(args: Array[String]): Unit = {
val lst=List(1,23,45,3)
val lst1=(lst :\ List[Int]())(_:: _)//:\foldRight
val lst1_re=(lst :\ List[Int]())((x,y)=>(y:+x))
val lst2=(List[Int]() /: lst)(_:+_)// /:foldLeft
val lst2_re=(List[Int]() /: lst)((x,y)=>y+:x)
println(lst1)
println(lst2)
println(lst2_re)
println(lst1_re)
}
}
4.根据 flatMap 实现一个variance(方差)函数,如果一个序列的平均值m,variance是对序列中的每一个元素x进行 math.pow(x-m,2) def variances(xs: Seq[Double]): Option[Double]
代码
用的是map,用flatMap不知道怎么写
object Varience {
def variances(xs: Seq[Double]): Option[Double] = {
val len = xs.size
val m = xs.sum / xs.size
Some(xs.map(x=>math.pow(x-m,2)).sum/len)
}
def main(args: Array[String]): Unit = {
val xs = Seq(1.0, 1, 1, 1)
println( variances(xs))
}
}
5.统计字符串中字母出现的频率映射,例如字符串 “scalajavajavascript”返回Map[Char,Int]。用aggregate 方法
代码
import scala.collection.immutable.HashMap
object FrequenceMap {
def main(args: Array[String]): Unit = {
val str = "scalajavajavascript"
val res = str.par.aggregate(HashMap[Char, Int]())(
(hashMap, char) => {
//相当于map阶段,处理成key,value形式
hashMap + (char -> (hashMap.getOrElse(char, 0) + 1))
}
(map1, map2) => {
(map1.keySet ++ map2.keySet).foldLeft(HashMap[Char, Int]()) {
(hashMap, key) => {
hashMap + (key -> (map1.getOrElse(key, 0) + map2.getOrElse(key, 0)))
}
}
}
)
println(res)
}
}