2016-09-23 28 views
0

我正在尋找一種將scala數組轉換爲包含數組中發生項目頻率的映射的整潔方式。將scala數組轉換爲項目數映射

例如, :

鑑於像數組:

val arr = Array("one", "one", "two", "three", "one", "three") 

我要地圖:

Map("one" -> 3, "two" -> 1, "three" -> 2) 

我可以寫一個函數做到這一點,如

import scala.collection.mutable 

def counter[T](arr: Array[T]) = { 
    val temp = mutable.Map[T, Int]() 
    for (i <- arr) { 
    if (temp.contains(i)) temp(i) += 1 
    else temp(i) = 1 
    } 
    temp 
} 

counter(arr) 

我想了解這是否可以更有效地完成。

回答

4

我會使用groupBy(identity)mapValues(_.length)

scala> val arr = Array("one", "one", "two", "three", "one", "three") 
arr: Array[String] = Array(one, one, two, three, one, three) 

scala> arr.groupBy(identity).mapValues(_.length) 
res0: scala.collection.immutable.Map[String,Int] = Map(one -> 3, three -> 2, two -> 1) 

更新:這不是效率比你的代碼(我認爲這是不可能擊敗),但它絕對是更具可讀性。 groupBy method將所有相同的(因爲我們使用identity)值彙總到一個Array,與僅增加計數相比,它有一些開銷。

更新2:正如評論指出的那樣,輸出不可序列因爲mapValues只是包裝的地圖並評估各get功能。您可以包裹地圖上兌現地圖由map(identity)

arr.groupBy(identity).mapValues(_.length).map(identity) 

,但它不是很漂亮的代碼。

+0

謝謝! +1,以提高可讀性。這種方式拋出一個''java.io.NotSerializableException''錯誤,雖然在Spark中做同樣的事情。因此接受了替代答案。 – septra

6
arr.groupBy(identity).map{case (x,y) => x -> y.size} 
相關問題