1. 程式人生 > 其它 >實驗2-Scala程式設計初級實踐-題目

實驗2-Scala程式設計初級實踐-題目

1. 計算級數

請用指令碼的方式程式設計計算並輸出下列級數的前 n 項之和 Sn,直到 Sn 剛好大於或等於 q 為止,其中 q 為大於 0 的整數,其值通過鍵盤輸入。

例 如 , 若 q 的 值 為 50.0 , 則 輸 出 應 為 : Sn=50.416695 。 請 將 源 文 件 保 存 為 exercise2-1.scala,在REPL模式下測試執行,

測試樣例:q=1時,Sn=2;q=30時,Sn=30.891459; q=50 時,Sn=50.416695。

import scala.io.StdIn

object sy1 {
  def main(args: Array[String]): Unit 
= { var p = StdIn.readInt() var s: Float = 0 var n: Float = 1 while (s<p){ s=s+(n+1)/n n=n+1 } println(s"Sn=${s}") } }

在命令列終端執行,先在下面畫出的資料夾下建立sy2.scala檔案,將上述程式碼複製到檔案中,然後直接在Windows cmd下或者linux終端下輸入scala sy2.scala即可執行

2. 模擬圖形繪製

對於一個圖形繪製程式,用下面的層次對各種實體進行抽象。定義一個 Drawable 的特 質,其包括一個 draw 方法,預設實現為輸出物件的字串表示。定義一個 Point 類表示點, 其混入了 Drawable 特質,幷包含一個 shift 方法,用於移動點。所有圖形實體的抽象類為Shape,其建構函式包括一個 Point 型別,表示圖形的具體位置(具體意義對不同的具體圖 形不一樣)。Shape 類有一個具體方法 moveTo 和一個抽象方法 zoom,其中 moveTo 將圖形從 當前位置移動到新的位置, 各種具體圖形的 moveTo 可能會有不一樣的地方。zoom 方法實 現對圖形的放縮,接受一個浮點型的放縮倍數引數,不同具體圖形放縮實現不一樣。繼承 Shape 類的具體圖形型別包括直線類 Line 和圓類 Circle。Line 類的第一個引數表示其位置, 第二個引數表示另一個端點,Line 放縮的時候,其中點位置不變,長度按倍數放縮(注意, 縮放時,其兩個端點資訊也改變了),另外,Line 的 move 行為影響了另一個端點,需要對 move 方法進行過載。Circle 類第一個引數表示其圓心,也是其位置,另一個引數表示其半 徑,Circle 縮放的時候,位置引數不變,半徑按倍數縮放。另外直線類 Line 和圓類 Circle 都混入了 Drawable 特質,要求對 draw 進行過載實現,其中類 Line 的 draw 輸出的資訊樣式 為“Line:第一個端點的座標--第二個端點的座標)”,類 Circle 的 draw 輸出的資訊樣式為 “Circle center:圓心座標,R=半徑”。如下的程式碼已經給出了 Drawable 和 Point 的定義, 同時也給出了程式入口 main 函式的實現,請完成 Shape 類、Line 類和 Circle 類的定義。

//特質
trait Drawable { def draw(): Unit
={ println(this.toString) } } //Shape類 abstract class Shape(var point:Point) { def moveTo(changePoint: Point)= { point = changePoint } def zoom(float: Float) }
//Point類
case class Point(var x:Double,var y:Double) extends Drawable { def shift(deltaX:Double,deltaY:Double): Unit
={ x+=deltaX y+=deltaY } }
//Circle類
//為什麼子類的的引數不能與父類的名稱相同,在這裡如果將下面的兩point1都修改成point則會出現意想不到的結果 class Circle( point1: Point, var r:Float) extends Shape(point1) with Drawable { override def zoom(float: Float) { r = r*float } override def draw(): Unit = { println(s"Circle center:(${point.x},${point.y}),R=$r") } }
//Line類
class Line(var startPoint:Point,var endPoint:Point) extends Shape(startPoint) with Drawable { override def moveTo(changePoint: Point){ val changeX = changePoint.x - startPoint.x val changeY = changePoint.y - startPoint.y startPoint = changePoint endPoint.x = endPoint.x+changeX endPoint.y = endPoint.y+changeY } def zoom(float: Float): Unit ={ var centerX = (startPoint.x+endPoint.x)/2 var centerY = (startPoint.y+endPoint.y)/2 var absXDiv2 = (startPoint.x-endPoint.x).abs/2 var absYDiv2 = (startPoint.y-endPoint.y).abs/2 if((startPoint.x-endPoint.x)>0){ startPoint.x = centerX+ float*absXDiv2 endPoint.x = centerX - float*absXDiv2 }else{ endPoint.x = centerX + float*absXDiv2 startPoint.x = centerX - float*absXDiv2 } if((startPoint.y - endPoint.y)>0){ startPoint.y = centerY+float*absYDiv2 endPoint.y = centerY-float*absYDiv2 }else{ endPoint.y = centerY+float*absYDiv2 startPoint.y = centerY - float*absYDiv2 } } override def draw(): Unit ={ println(s"Line:$startPoint--$endPoint") } }
//測試類 object MyDraw { def main(args: Array[String]): Unit
= { val p=new Point(10,30) p.draw; val line1 = new Line(Point(0,0),Point(20,20)) line1.draw line1.moveTo(Point(5,5)) //移動到一個新的點 line1.draw line1.zoom(2) //放大兩倍 line1.draw val cir= new Circle(Point(10,10),5) cir.draw cir.moveTo(Point(30,20)) cir.draw cir.zoom(0.5f) cir.draw } }

執行結果:

3. 統計學生成績

感覺這道題目比較難,沒有完全理解下面的程式

object test2 {
  def main(args: Array[String]): Unit = {
    val inputFile = Source.fromFile("test/test1.txt")
    //"\\s+"是字串正則表示式。將每行按空白符(包括空格/製表符)分開
    //由於可能涉及多次遍歷,同tolist將Iterator裝為List
    val originalData = inputFile.getLines().map{_.split("\\s+")}.toList
    val courseNames = originalData.head.drop(2)//獲取第一行中的課程名
    println(courseNames.toList)
    val allStudents = originalData.tail//去除第一行資料
    val courseNum = courseNames.length
    //統計函式,引數為需要常用的統計行
    //用到了外部變數courseNum,屬於閉包函式
    def statistc(lines:List[Array[String]]) ={
      //for推導式,對每門課程生成一個三元組,分別表示總分,最低分,最高分
      (for(i<-2 to courseNum+1) yield{
        //取出需要統計的列
        val temp = lines map { elem => elem(i).toDouble }
        (temp.sum,temp.min,temp.max)
        }) map{case (total,min,max) => (total/lines.length,min,max)
      }//最後一個map對for的結果進行修改,將總分轉為平均分
    }
    //輸出結果
    def printResult(theresult:Seq[(Double,Double,Double)]): Unit ={
      //遍歷前呼叫zip方法將課程名容器和結果容器合併,合併結果為二元容器
      (courseNames zip theresult) foreach{
        case (course,result)=>
          println(f"${course+":s"}%-10s${result._1}%5.2f${result._2}%8.2f${result._3}%8.2f")
      }
    }
    //分別呼叫兩個函式統計全體學生並輸出結果
    val allResult = statistc(allStudents)
    println("course average min max")
    printResult(allResult)

    //按性別劃分為兩個容器
    val (maleLines,femaleLines) = allStudents partition
    {_(1)=="male"}
    //分別呼叫兩個函式統計男同學並輸出結果
    val maleResult = statistc(maleLines)
    println("course average min max")
    printResult(maleResult)
    // 分別呼叫兩個函式統計男學生並輸出結果
    val femaleResult = statistc(femaleLines)
    println("course average min max")
    printResult(femaleResult)
  }
}

執行結果: