septra septra - 1 year ago 119
Scala Question

Convert scala array to Map of item counts

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


I'd like to know if this can be done more efficiently.

Answer Source

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:


but it's not very nice code.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download