ivaneye.com

快学Scala习题解答—第十三章 集合

集合

编写一个函数,给定字符串,产出一个包含所有字符的下标的映射。举例来说:indexes("Mississippi")应返回一个映射,让'M'对应集{0},'i'对应集{1,4,7,10},依此类推。使用字符到可变集的映射。另外,你如何保证集是经过排序的?

更新scala到版本2.10.0。有可变的可排序的Set,实际上还是TreeSet

import collection.mutable.{Map,HashMap,SortedSet}
def indexs(str:String):Map[Char,SortedSet[Int]]={
  var map = new HashMap[Char, SortedSet[Int]]();
  var i = 0;
  str.foreach{
    c=>
      map.get(c) match{
        case Some(result) => map(c) = result + i
        case None => map += (c-> SortedSet{i})
      }
      i += 1
  }
  map
}
println(indexs("Mississippi"))

重复前一个练习,这次用字符到列表的不可变映射。

import collection.immutable.HashMap
import collection.mutable.ListBuffer
def indexs(str:String):Map[Char,ListBuffer[Int]]={
  var map = new HashMap[Char, ListBuffer[Int]]()
  var i = 0
  str.foreach{
    c=>
      map.get(c) match{
        case Some(result) => result += i
        case None => map += (c-> ListBuffer{i})
      }
      i += 1
  }
  map
}
println(indexs("Mississippi"))

快学Scala习题解答—第十二章 高阶函数

高阶函数

编写函数values(fun:(Int)=>Int,low:Int,high:Int),该函数输出一个集合,对应给定区间内给定函数的输入和输出。比如,values(x=>x*x,-5,5)应该产出一个对偶的集合(-5,25),(-4,16),(-3,9),...,(5,25)

object Test extends App {
  def values(fun: (Int) => Int, low: Int, high: Int) = {
    var arr = List[(Int,Int)]()
    low to high foreach {
      num =>
      arr = (num, fun(num)) :: arr
    }
    arr
  }
  println(values(x => x * x, -5, 5).mkString)
}

如何用reduceLeft得到数组中的最大元素?

object Test extends App {
  val arr = Array(3,2,6,8,4,6,9,3,6,7,1,2)
  print(arr.reduceLeft((a,b)=>if (a>b) a else b))
}

用to和reduceLeft实现阶乘函数,不得使用循环或递归

println(1 to 10 reduceLeft(_ * _))

前一个实现需要处理一个特殊情况,即n<1的情况。展示如何用foldLeft来避免这个需要。

println((1 to -10).foldLeft(1)(_ * _))

快学Scala习题解答—第十一章 操作符

操作符

根据优先级规则,3 + 4 -> 5和3 -> 4 + 5是如何被求值的?

在REPL中执行即可得到结果。都是从左至右执行

BigInt类有一个pow方法,但没有用操作符字符。Scala类库的设计者为什么没有选用**(像Fortran那样)或者^(像Pascal那样)作为乘方操作符呢?

Scala中的操作符就是方法,其优先级是根据首字母来判断的,优先级如下

最高优先级:除以下字符外的操作符字符
 * / %
+ -
:
= !
< >
&
ˆ
|
非操作符
最低优先级:赋值操作符

一般乘方的操作符是优于乘法操作的,如果使用**作为乘方的话,那么其优先级则与*相同,而如果使用^话,则优先级低于*操作。优先级都是有问题的。故没有使用这两种操作符

快学Scala习题解答—第十章 特质

特质

java.awt.Rectangle类有两个很有用的方法translate和grow,但可惜的是像java.awt.geom.Ellipse2D这样的类没有。在Scala中,你可以解决掉这个问题。定义一个RenctangleLike特质,加入具体的translate和grow方法。提供任何你需要用来实现的抽象方法,以便你可以像如下代码这样混入该特质:

val egg = new java.awt.geom.Ellipse2D.Double(5,10,20,30) with RectangleLike
egg.translate(10,-10)
egg.grow(10,20)

使用自身类型使得trait可以操作x,y

import java.awt.geom.Ellipse2D
trait RectangleLike{
  this:Ellipse2D.Double=>
  def translate(x:Double,y:Double){
    this.x = x
    this.y = y
  }
  def grow(x:Double,y:Double){
    this.x += x
    this.y += y
  }
}
object Test extends App{
  val egg = new Ellipse2D.Double(5,10,20,30) with RectangleLike
  println("x = " + egg.getX + " y = " + egg.getY)
  egg.translate(10,-10)
  println("x = " + egg.getX + " y = " + egg.getY)
  egg.grow(10,20)
  println("x = " + egg.getX + " y = " + egg.getY)
}

快学Scala习题解答—第九章 文件和正则表达式

文件和正则表达式

编写一小段Scala代码,将某个文件中的行倒转顺序(将最后一行作为第一行,依此类推)

import io.Source
import java.io.PrintWriter
val path = "test.txt"
val reader = Source.fromFile(path).getLines()
val result = reader.toArray.reverse
val pw = new PrintWriter(path)
result.foreach(line => pw.write(line + "\n"))
pw.close()

编写Scala程序,从一个带有制表符的文件读取内容,将每个制表符替换成一组空格,使得制表符隔开的n列仍然保持纵向对齐,并将结果写入同一个文件

import io.Source
import java.io.PrintWriter
val path = "test.txt"
val reader = Source.fromFile(path).getLines()
val result = for ( t <- reader) yield t.replaceAll("\\t","    ")
val pw = new PrintWriter(path)
result.foreach(line => pw.write(line + "\n"))
pw.close()

快学Scala习题解答—第八章 继承

继承

扩展如下的BankAccount类,新类CheckingAccount对每次存款和取款都收取1美元的手续费

class BankAccount(initialBalance:Double){
    private var balance = initialBalance
    def deposit(amount:Double) = { balance += amount; balance}
    def withdraw(amount:Double) = {balance -= amount; balance}
}

继承语法的使用。代码如下

class CheckingAccount(initialBalance:Double) extends BankAccount(initialBalance){
  override def deposit(amount: Double): Double = super.deposit(amount - 1)
  override def withdraw(amount: Double): Double = super.withdraw(amount + 1)
}

扩展前一个练习的BankAccount类,新类SavingsAccount每个月都有利息产生(earnMonthlyInterest方法被调用),并且有每月三次免手续费的存款或取款。在earnMonthlyInterest方法中重置交易计数。

class SavingsAccount(initialBalance:Double) extends BankAccount(initialBalance){
  private var num:Int = _
  def earnMonthlyInterest()={
    num = 3
    super.deposit(1)
  }
  override def deposit(amount: Double): Double = {
    num -= 1
    if(num < 0) super.deposit(amount - 1) else super.deposit(amount)
  }
  override def withdraw(amount: Double): Double = {
    num -= 1
    if (num < 0) super.withdraw(amount + 1) else super.withdraw(amount)
  }
}

快学Scala习题解答—第七章 包和引入

包和引入

编写示例程序,展示为什么

package com.horstmann.impatient

不同于

package com
package horstmann
package impatient

分别使用package的效果如下

package com {
  class T1() {}
  package horstmann {
    class T2(t: T1) {}
    package impatient {
      class T3(t1: T1, t2: T2) {}
    }
  }
}

子包里的类可以使用父包里的类。但是第一种方式不可以

package com.horstmann.impatient{
  class T4(t1:T1,t3:T3)      //无法找到T1
}