1. 程式人生 > >scala習題(14)——模式匹配和樣例類

scala習題(14)——模式匹配和樣例類

14.1 JDK發行包有一個src.zip檔案包含了JDK的大多數原始碼。解壓並搜尋樣例標籤(用正則表示式case [^:]+:)。然後查詢以//開頭幷包含[Ff]alls?thr的註釋,捕獲類似// Falls through或// just fall thru這樣的註釋。假定JDK的程式設計師們遵守Java編碼習慣,在該寫註釋的地方寫下了這些註釋,有多少百分比的樣例是會掉入到下一個分支的?
沒看懂=。=
14.2 利用模式匹配,編寫一個swap函式,接受一個整數的對偶,返回對偶的兩個組成部件互換位置的新對偶
偏函式的用法,在使用時可以制定引數型別

 def swap[W,Y](tup:(W,Y
))={ tup match{ case (a,b) => (b,a); } }

14.3 利用模式匹配,編寫一個swap函式,交換陣列中的前兩個元素的位置,前提條件是陣列長度至少為2
陣列匹配,剩餘所有引數的表示方式為_*,用變數名稱代替的方式為ar @_*

 def swap(arr:Array[Int])={
    arr match{
      case Array(a,b,[email protected]_*) => Array(b,a,ar);
    }
  }

14.4 新增一個樣例類Multiple,作為Item的子類。舉例來說,Multiple(10,Article(“Blackwell Toster”,29.95))描述的是10個烤麵包機。當然了,你應該可以在第二個引數的位置接受任何Item,無論是Bundle還是另一個Multiple。擴充套件price函式以應對新的樣例。

abstract class item;
  case class Article(description:String,price:Double) extends item;
  case class Bundle(description:String,discount:Double,items:item*) extends item;
  case class Multiple(count:Int,item :item) extends item;
  def price(it:item):Double = it match{
    case Article(_,p)=>p;
    case
Bundle(_,disc,its @ _ *)=>its.map(price).sum -disc; case Multiple(count,it) => price(it)*count; }

14.5 我們可以用列表製作只在葉子節點存放值的樹。舉例來說,列表((3 8) 2 (5))描述的是如下這樣一棵樹:
*
/ | \
* 2 *
/ \ |
3 8 5
不過,有些列表元素是數字,而另一些是列表。在Scala中,你不能擁有異構的列表,因此你必須使用List[Any]。編寫一個leafSum函式,計算所有葉子節點中的元素之和,用模式匹配來區分數字和列表。

 def LeafSum(li:List[Any]):Int={
    var sum=0;
    li.foreach{
      l => l match{
        case list:List[Any] => sum=sum+LeafSum(list);
        case t:Int=>sum=sum+t;
      }
    }
    sum;
  }
  println(LeafSum(List(List(3,8),2,List(5))));

14.6 製作這樣的樹更好的做法是使用樣例類。我們不妨從二叉樹開始。

sealed abstract class BinaryTree
case class Leaf(value : Int) extends BinaryTree
case class Node(left : BinaryTree,right : BinaryTree) extends BinaryTree

編寫一個函式計算所有葉子節點中的元素之和。

使用樣例類建議使用密封類的形式,代表本類只在本檔案內可見

 sealed abstract class BinaryTree;
  case class Leaf(value:Int) extends BinaryTree;
  case class Node(left:BinaryTree,right:BinaryTree) extends BinaryTree;
  case class Nodes(btree:BinaryTree*) extends BinaryTree;
  case class sNode(oper:String,node:BinaryTree*) extends BinaryTree;
  def leafsum(btree:BinaryTree):Int={
    var sum=0;
    btree match{
      case Node(a,b) =>sum=sum+leafsum(a)+leafsum(b);
      case Leaf(a) => sum=sum+a;
      case Nodes([email protected]_*) => sum=sum+btr.map(leafsum).sum;
    }
    sum
  }

14.7 擴充套件前一個練習中的樹,使得每個節點可以有任意多的後代,並重新實現leafSum函式。第五題中的樹應該能夠通過下述程式碼表示:

sealed abstract class BinaryTree;
  case class Leaf(value:Int) extends BinaryTree;
  case class Node(left:BinaryTree,right:BinaryTree) extends BinaryTree;
  case class Nodes(btree:BinaryTree*) extends BinaryTree;
  case class sNode(oper:String,node:BinaryTree*) extends BinaryTree;
  def leafsum(btree:BinaryTree):Int={
    var sum=0;
    btree match{
      case Node(a,b) =>sum=sum+leafsum(a)+leafsum(b);
      case Leaf(a) => sum=sum+a;
      case Nodes([email protected]_*) => sum=sum+btr.map(leafsum).sum;
    }
    sum
  }

14.8 擴充套件前一個練習中的樹,使得每個非葉子節點除了後代之外,能夠存放一個操作符。然後編寫一個eval函式來計算它的值。舉例來說:
+
/ | \
* 2 -
/ \ |
3 8 5
上面這棵樹的值為(3 * 8) + 2 + (-5) = 21

 sealed abstract class BinaryTree;
  case class Leaf(value:Int) extends BinaryTree;
  case class Node(left:BinaryTree,right:BinaryTree) extends BinaryTree;
  case class Nodes(btree:BinaryTree*) extends BinaryTree;
  case class sNode(oper:String,node:BinaryTree*) extends BinaryTree;
  def leafsum(btree:BinaryTree):Int={
    var sum=0;
    btree match{
      case Node(a,b) =>sum=sum+leafsum(a)+leafsum(b);
      case Leaf(a) => sum=sum+a;
      case Nodes([email protected]_*) => sum=sum+btr.map(leafsum).sum;
    }
    sum
  }
  def eval(btree:BinaryTree):Int={

    btree match{
      case sNode(oper,[email protected]_*) => if(oper=="+") btr.map(eval).sum else if(oper=="*") btr.map(eval).reduceLeft(_*_) else if(oper=="-") btr.map(eval).foldLeft(0)(_-_) else  btr.map(eval).reduceLeft(_/_)
      case Leaf(v)=>v
    }


  }

14.9 編寫一個函式,計算List[Option[Int]]中所有非None值之和。不得使用match語句。

 def evalList(list:List[Option[Int]]):Int={
   list.map(_.getOrElse(0)).sum;
  }

14.10 編寫一個函式,將兩個型別為Double=>Option[Double]的函式組合在一起,產生另一個同樣型別的函式。如果其中一個函式返回None,則組合函式也應返回None。例如:

  def f(x:Double) = if(x>=0) Some(sqrt(x)) else None;
  def g(x:Double) = if(x!=1) Some(1/(x-1)) else None;
  def compose(x:Double=>Option[Double],y:Double=>Option[Double]):(Double=>Option[Double])={
    (f:Double) => if(x(f)==None || y(f)==None) None else if(x(f).get> y(f).get) x(f) else y(f)
  }