如下爲第37講List的foldLeft、foldRight、sort操做代碼實戰函數
package com.parllay.scala.dataset/** * Created by richard on 15-7-22. */object List_Fold_Sort { def main(args: Array[String]) { /** * Scala深刻淺出實戰經典之 List的foldLeft、foldRight、sort操做代碼實戰 * * 本質上說,fold函數將一種格式的輸入數據轉化成另一種格式返回。fold, foldLeft和foldRight這三個函數除了有一點點不一樣外,作的事情差很少。 val numbers = List(5, 4, 8, 6, 2) numbers.fold(0) { (z, i) => z + i } // result = 25 List中的fold方法須要輸入兩個參數:初始值以及一個函數。輸入的函數也須要輸入兩個參數:累加值和當前item的索引。 那麼上面的代碼片斷髮生了什麼事? 代碼開始運行的時候,初始值0做爲第一個參數傳進到fold函數中,list中的第一個item做爲第二個參數傳進fold函數中。 一、fold函數開始對傳進的兩個參數進行計算,在本例中,僅僅是作加法計算,而後返回計算的值; 二、Fold函數而後將上一步返回的值做爲輸入函數的第一個參數,而且把list中的下一個item做爲第二個參數傳進繼續計算,一樣返回計算的值; 三、第2步將重複計算,直到list中的全部元素都被遍歷以後,返回最後的計算值,整個過程結束; 四、這雖然是一個簡單的例子,讓咱們來看看一些比較有用的東西。早在後面將會介紹foldLeft函數,並解釋它和fold之間的區別, 目前,你只須要想象foldLeft函數和fold函數運行過程同樣。 fold, foldLeft, and foldRight之間的區別 主要的區別是fold函數操做遍歷問題集合的順序。foldLeft是從左開始計算,而後往右遍歷。foldRight是從右開始算,而後往左遍歷。 而fold遍歷的順序沒有特殊的次序。來看下這三個函數的實現吧(在TraversableOnce特質裏面實現) def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op) def foldLeft[B](z: B)(op: (B, A) => B): B = { var result = z this.seq foreach (x => result = op(result, x)) result } def foldRight[B](z: B)(op: (A, B) => B): B = reversed.foldLeft(z)((x, y) => op(y, x)) 因爲fold函數遍歷沒有特殊的次序,因此對fold的初始化參數和返回值都有限制。在這三個函數中,初始化參數和返回值的參數類型必須相同。 第一個限制是初始值的類型必須是list中元素類型的超類。在咱們的例子中,咱們的對List[Int]進行fold計算,而初始值是Int類型的,它是List[Int]的超類。 第二個限制是初始值必須是中立的(neutral)。也就是它不能改變結果。好比對加法來講,中立的值是0;而對於乘法來講則是1,對於list來講則是Nil。 順便說下,其實foldLeft和foldRight函數還有兩個縮寫的函數: def /:[B](z: B)(op: (B, A) => B): B = foldLeft(z)(op) def :\[B](z: B)(op: (A, B) => B): B = foldRight(z)(op) scala> (0/:(1 to 100))(_+_) res32: Int = 5050 scala> ((1 to 100):\0)(_+_) res24: Int = 5050 */ println((1 to 100).foldLeft(0)(_+_)) println((0 /: (1 to 100))(_+_)) println((1 to 5).foldRight(100)(_-_)) println(((1 to 5):\ 100)(_-_)) println(List(1, -3, 4, 2, 6) sortWith(_<_)) println(List(1, -3, 4, 2, 6) sortWith(_>_)) }}