2014-06-14 218 views
1

如何在斯卡拉使用減少功能?有這樣的內置函數嗎? 我已經實現了一個程序來查找斯卡拉字數。斯卡拉 - 減少功能

object count { 
    def main(args: Array[String]) { 
     val fruits = List("apple", "apple", "orange", "apple", "mango", "orange") 
     val word = fruits.flatMap(_.split("\n")) 
     val Map = word.map(word => (word,1)).groupBy(_._1) 
     val reduce = Map.map(word => (word._1,word._2.foldLeft(0)((sum,c) => sum+ c._2))) 
     println(reduce)  }} 

如何用reduce函數替換foldleft?

+1

有一個'reduce',但'foldLeft'在這種情況下更合適,因爲'reduce'不接受默認值,所以它會在空列表上失敗。 –

+0

如果我們使用reduce而不是功能如何? – user2841047

+0

我剛剛提出這個問題。在目前的狀態下,它需要改進它的措辭...但我仍然認爲這個問題有一定的教學價值,並且對中級/初級階梯用戶很有用 – jayunit100

回答

12

整個上面的例子應該是這樣

fruits groupBy(word => word) mapValues(_.size) 

或這樣來實現替代倍

val reduce = Map.map(word => (word._1,word._2.size)) 

,但如果你絕對肯定必須使用減少完全相同的代碼,這將是像這樣的東西

val reduce = Map.map(word => (word._1,word._2.map(_=>1).reduce(_+_))) 
+0

很酷的例子。對於我使用Scala版本2.11.4,第二條語句會得到一個錯誤,但是這是有效的:fruits groupBy(word => word)map(word =>(word._1,word._2.size)) –

+0

感謝您的好評回答。順便說一句,而不是使用(單詞=>單詞),(身份)也可以用於參數和返回值是相同的。 – noego

0

不,沒有內置函數的行爲如此。您可以使用mapValues而不是第二個map來簡化它,但沒有類似的foldValues

1

你的例子可以做得更簡單,因爲fol低點:

> fruits.groupBy(identity).mapValues(_.size) 
res176: Map[String, Int] = Map("mango" -> 1, "orange" -> 2, "apple" -> 3) 

但是,如果您想並行化並使用MapReduce模式,那麼reduce就很有用。如果你不併行化,你只需要依次減少列表(1,1,1,1 ...)。比較:

> List(1,1,1,1,1,1,1).reduce{(a,b) => println(s"$a+$b=${a+b}"); a + b} 
1+1=2 
2+1=3 
3+1=4 
4+1=5 
5+1=6 
6+1=7 
res187: Int = 7 

與並行版本(注意par法):

> List(1,1,1,1,1,1,1).par.reduce{(a,b) => println(s"$a+$b=${a+b}"); a + b} 
1+1=2 
1+1=2 
1+2=3 
1+1=2 
2+2=4 
3+4=7 
res188: Int = 7 

您可以通過定義常用reduceByKey功能按如下方式使用你的情況的MapReduce模式:

implicit class MapReduceTraversable[T, N](val traversable: Traversable[(T, N)]) { 
    def reduceByKey(f: (N, N) => N) = traversable.par.groupBy(_._1).mapValues(_.map(_._2)).mapValues(_.reduce(f)) 
} 

val fruits = List("apple", "apple", "orange", "apple", "mango", "orange", "apple", "apple", "apple", "apple") 

fruits.map(f => (f,1)).reduceByKey(_ + _) 

res2: collection.parallel.ParMap[String, Int] = ParMap(orange -> 2, mango -> 1, apple -> 7) 

您可以像以前一樣調試它:

fruits.map(f => (f,1)).reduceByKey{(a,b) => println(s"$a+$b=${a+b}"); a + b} 

1+1=2 
1+1=2 
2+1=3 
3+1=4 
4+1=5 
5+1=6 
6+1=7 
res9: Map[String, Int] = Map("mango" -> 1, "orange" -> 2, "apple" -> 7)