GraphLearner
GraphLearner

Reputation: 327

Transforming Map using map in scala

Given a string I want to create a map that for each character in a string will give the number of times the character occurs in a string. The following function makes a map from character to a list of Strings.

def wordOccurrences(w: String) = {
  val lower = w.toLowerCase.toList
  lower.groupBy(t => t)
}

Now I wanted to alter the last line to:

lower.groupBy(t => t) map ( (x,y) => x -> y.length)

But it doesn't work, can someone explain why and how to fix it?

Upvotes: 0

Views: 69

Answers (2)

stefanobaghino
stefanobaghino

Reputation: 12794

For mapping purposes, a Map[K, V] is an Iterable[(K, V)] (notice the extra pair of parentheses, identifying a tuple type), meaning that when you map over it you have pass a function that goes from (K, V) to your target type.

What you are doing, however, is passing a function that takes two independent arguments, rather then a single tuple argument.

The difference can be seen by inspecting the types of these two functions in the Scala shell:

scala> :t (a: Int, b: Int) => a + b
(Int, Int) => Int

scala> :t (p: (Int, Int)) => p._1 + p._2
((Int, Int)) => Int

Notice how the former takes two arguments while the latter takes a single tuple.

What you can do is pass a function which decomposes the tuple so that you can bind the components of the tuple independently:

lower.groupBy(t => t) map { case (x, y) => x -> y.length }

or alternatively pass a function which uses the tuple without deconstructing it

lower.groupBy(t => t) map (p => p._1 -> p._2.length)

Note

Dotty, which is the current project Scala's original author Martin Odersky is working on and that will probably become Scala 3, supports the syntax you are proposing, calling the feature function arity adaptation. This has been discussed, along with other feature, in Odersky's 2016 Keynote at Scala eXchange, "From DOT to Dotty" (here the video taped at 2017 Voxxed Days CERN).

Upvotes: 2

Harald Gliebe
Harald Gliebe

Reputation: 7544

You can use

 lower.groupBy(t => t).mapValues(_.length)

Upvotes: 2

Related Questions