你想要遍歷有序集合的全部元素,而且隨着你對集合元素的遍歷,對比兩個相鄰的元素es6
使用reduceLeft, foldLeft, reduceRight, foldRight來遍歷集合的元素,你的方法做用在相鄰的兩個元素上,從第一次要遍歷的兩個相鄰元素開始,把你的方法做用在這兩個元素上獲得返回值,而後把你的方法繼續做用在返回值和集合中第三要遍歷的元素獲得的返回值,再繼續和第四個要遍歷的元素做用。。。直到遍歷完最後一個元素爲止:算法
scala> val a = Array(12, 6, 15, 2, 20, 9) a: Array[Int] = Array(12, 6, 15, 2, 20, 9) scala> a.reduceLeft(_ + _) res32: Int = 64
這個例子是這樣的:12+6=18, 18+15=33, 33+2=35, 35+20=55, 55+9=64,就是對集合的全部元素求和
ide
接下來你會看到如何使用reduceLeft來計算集合元素的乘積和求最大最小值:函數
scala> a.reduceLeft(_ * _) res33: Int = 388800 scala> a.reduceLeft(_ min _) res34: Int = 2 scala> a.reduceLeft(_ max _) res35: Int = 20
咱們來看看reduceLeft的執行細節:es5
val findMax = (x: Int, y: Int) => { val winner = x max y println(s"compared $x to $y, $winner was larger") winner }
scala> a.reduceLeft((x,y) => findMax(x,y)) compared 12 to 6, 12 was larger compared 12 to 15, 15 was larger compared 15 to 2, 15 was larger compared 15 to 20, 20 was larger compared 20 to 9, 20 was larger res38: Int = 20
上面的輸出信息展現了reduceLeft是如何遍歷集合中的每個元素,並在每一步時是如何調用傳入的函數操做集合元素的。咱們來總結一下reduceLeft的操做步驟:
spa
reduceLeft開始調用findMax方來來比較集合的前兩個元素,12和6,findMax方法返回12,由於12>6scala
reduceLeft接下來使用第一次調用findMax的返回值12和集合的第三個元素15,調用findMax(12, 15),由於15>12因此findMax返回15debug
reduceLeft接下來用每一步執行的返回值和集合的下一個元素傳入findMax方法,返回較大的值,直到遍歷完集合的最後一個元素,返回最大值20code
咱們來換種方法來模擬reduceLeft的功能:ip
// you provide the sequence 'seq' and the function 'f' var result = seq(0) for (i <- 1 until seq.length) { val next = seq(i) result = f(result, next) }
一個關於reduceLeft方法很是微妙而且重要的事項:傳入的方法的返回值類型必須是要和集合中存儲的數據類型相同的。這是很是必要的,由於reduceLeft會對比方法的返回值和集合中的下一個元素。
正如你想象的,集合包涵的數據類型能夠是任何你想要的。舉個例子,遍歷一個字符串序列經過一個方法來肯定最長的活着最短的字符串:
scala> val peeps = Vector("al", "hannah", "emily", "christina", "aleka") peeps: scala.collection.immutable.Vector[String] = Vector(al, hannah, emily, christina, aleka) scala> peeps.reduceLeft((x,y) => if(x.length >= y.length) x else y) res5: String = christina
方法foldLeft與reduceLeft工做方法很想,可是它讓你指定一個值做爲第一個元素。下面這個例子真是了求和算法,第一個是reduceLeft方法,後面是foldLeft方法,咱們來看看它們的區別:
scala> val a = Array(1, 2, 3) a: Array[Int] = Array(1, 2, 3) scala> a.reduceLeft(_+_) res6: Int = 6 scala> a.foldLeft(100)(_+_) res7: Int = 106 scala> a.foldLeft(200)(_+_) res8: Int = 206
上面最後兩個例子中foldLeft分別使用了100,200做爲首元素,這個值直接影響到了最終求和的結果。若是你還從沒有見過這樣的語法,就拿foldLeft接受兩個參數列表來解釋一下把。第一個參數表接受一個字段,種子值。第二個參數表是一個你想要運行的代碼塊。方法reduceRight和foldRight執行方式和reduceLeft和foldLeft同樣,可是它們是從集合的最後一個元素開始遍歷,而後從右到左,直到遍歷到集合的開始位置。
在許多算法中,你可能並不在乎使用reduceLeft仍是reduceRight。在這種狀況下,你可使用reduce方法代替。Scala文檔中對reduce的說明:「對元素的操做順序是不明的或者不肯定的」。
可是還有許多算法會對兩種方法返回不一樣的結果。舉個例子,divide函數:
val divide = (x: Double, y: Double) => { val result = x / y println(s"divided $x by $y to yield $result") result } scala> def divide(x:Double, y:Double):Double = { | val result = x / y | println(s"divided $x by $y to yield $result") | result | } divide: (x: Double, y: Double)Double
定義一個集合,分別查看調用reduceLeft和reduceRight的結果:
scala> val a = Array(1.0, 2.0, 3.0) scala> a.reduceLeft((x,y) => divide(x,y)) divided 1.0 by 2.0 to yield 0.5 divided 0.5 by 3.0 to yield 0.16666666666666666 res10: Double = 0.16666666666666666 scala> a.reduceRight((x,y) => divide(x,y)) divided 2.0 by 3.0 to yield 0.6666666666666666 divided 1.0 by 0.6666666666666666 to yield 1.5 res11: Double = 1.5
方法scanLeft和scanRight也會變了整個集合,相似於reduceLeft和reduceRight,可是它們返回一個集合而不是一個值。
舉個例子,scanLeft產生一個集合,集合元素爲從左到右遍歷遍歷集合並對集合元素調用操做函數產生返回值。爲了理解這事如何工做的,咱們新建一個帶有debug的方法:
scala> def product(x:Int, y:Int):Int = { | val result = x * y | println(s"multiplied $x by $y to yield $result") | result | } product: (x: Int, y: Int)Int scala> val a = Array(1,2,3) a: Array[Int] = Array(1, 2, 3) scala> a.scanLeft(10)(product) multiplied 10 by 1 to yield 10 multiplied 10 by 2 to yield 20 multiplied 20 by 3 to yield 60 res12: Array[Int] = Array(10, 10, 20, 60)
正如你看到的,scanLeft返回了一個新的集合,而不是一個值。方法scanRight以一樣的方式工做,不過是從右到左遍歷集合。
那還有一些相關的方法,包含reduce,reduceLeftOption,reduceRightOption。
若是你關心reduce方法的狀況,那麼運行這段代碼來看看吧:
scala> def findMax(x:Int, y:Int):Int = { | Thread.sleep(10) | val winner = x max y | println(s"compared $x and $y, the winner is $winner") | winner | } findMax: (x: Int, y: Int)Int scala> val a = Array.range(0,50) a: Array[Int] = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49) scala> a.reduce(findMax) compared 0 and 1, the winner is 1 compared 1 and 2, the winner is 2 compared 2 and 3, the winner is 3 compared 3 and 4, the winner is 4 compared 4 and 5, the winner is 5 compared 5 and 6, the winner is 6 compared 6 and 7, the winner is 7 compared 7 and 8, the winner is 8 compared 8 and 9, the winner is 9 compared 9 and 10, the winner is 10 compared 10 and 11, the winner is 11 compared 11 and 12, the winner is 12 compared 12 and 13, the winner is 13 compared 13 and 14, the winner is 14 compared 14 and 15, the winner is 15 compared 15 and 16, the winner is 16 compared 16 and 17, the winner is 17 compared 17 and 18, the winner is 18 compared 18 and 19, the winner is 19 compared 19 and 20, the winner is 20 compared 20 and 21, the winner is 21 compared 21 and 22, the winner is 22 compared 22 and 23, the winner is 23 compared 23 and 24, the winner is 24 compared 24 and 25, the winner is 25 compared 25 and 26, the winner is 26 compared 26 and 27, the winner is 27 compared 27 and 28, the winner is 28 compared 28 and 29, the winner is 29 compared 29 and 30, the winner is 30 compared 30 and 31, the winner is 31 compared 31 and 32, the winner is 32 compared 32 and 33, the winner is 33 compared 33 and 34, the winner is 34 compared 34 and 35, the winner is 35 compared 35 and 36, the winner is 36 compared 36 and 37, the winner is 37 compared 37 and 38, the winner is 38 compared 38 and 39, the winner is 39 compared 39 and 40, the winner is 40 compared 40 and 41, the winner is 41 compared 41 and 42, the winner is 42 compared 42 and 43, the winner is 43 compared 43 and 44, the winner is 44 compared 44 and 45, the winner is 45 compared 45 and 46, the winner is 46 compared 46 and 47, the winner is 47 compared 47 and 48, the winner is 48 compared 48 and 49, the winner is 49 res13: Int = 49