集合
编写一个函数,给定字符串,产出一个包含所有字符的下标的映射。举例来说: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"))
高阶函数
编写函数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)(_ * _))
操作符
根据优先级规则,3 + 4 -> 5和3 -> 4 + 5是如何被求值的?
在REPL中执行即可得到结果。都是从左至右执行
BigInt类有一个pow方法,但没有用操作符字符。Scala类库的设计者为什么没有选用**(像Fortran那样)或者^(像Pascal那样)作为乘方操作符呢?
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代码,将某个文件中的行倒转顺序(将最后一行作为第一行,依此类推)
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()
继承
扩展如下的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)
}
}
包和引入
编写示例程序,展示为什么
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
}