Reputation: 1753
I'm looking for a neat way of converting a scala array to a map containing the frequency of the items occurring in the array.
For eg. :
Given an array like:
val arr = Array("one", "one", "two", "three", "one", "three")
I want a map:
Map("one" -> 3, "two" -> 1, "three" -> 2)
I can do this by writing a function such as
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)
I'd like to know if this can be done more efficiently.
Upvotes: 1
Views: 5145
Reputation: 740
I'd use groupBy(identity)
and 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)
Update: This isn't more efficient than your code (and I think it's not possible to beat), but it is definitely more readable. The groupBy
method aggregates all the identical (because we used identity
) values to one Array
, that has some overhead compared to just incrementing count.
Update 2: As noted in the comment, the output is not serializable because the mapValues
just wraps the map and evaluates the function on each get
. You can materialize the map by map(identity)
on the wrapped map:
arr.groupBy(identity).mapValues(_.length).map(identity)
but it's not very nice code.
Upvotes: 6