I have a Seq
of Strings.
val words = Seq("sad", "dsvc", "bbvv", "sf")
I'd like to use groupBy
to get a map where the key is the length of the string and value is a collection of strings of that length.
val output = Map(3 -> ("sad"), 4 -> ("dsvc","bbvv"), 2 -> ("sf"))
Still rather new to Scala so I can't quite figure out how to achieve this.
CodePudding user response:
Look at the signature of groupBy
on Seq:
def groupBy[K](f: (A) => K): immutable.Map[K, Seq[A]]
You have a Seq[String]
so you know A=String
. The method is asking you to provide an answer to "group by what?" in the form of the function f
, which gets that grouping criteria (of type K
) from a given value of type A
(i.e. your String). In your post you said you want to group by the string length, so K
is the length type, i.e. Int. You just need to pass a function that returns the length of the given string. Constructing this function is the "lambda" that Luis referred to in his comment. Once you pass that function to groupBy
, you get an immutable.Map[K, Seq[A]]
, i.e. a Map whose keys are the string length (K) and whose values are Sequences of strings (Seq[A]) matching that length.
There are a couple different syntaxes for constructing anonymous functions (lambdas): one where you use _
to represent the argument(s) of the function, and another where you make it look similar to a def
method definition. E.g.
_.length
or s => s.length
would work.
val words = Seq("sad", "dsvc", "bbvv", "sf")
words.groupBy(_.length)
// val res0: scala.collection.immutable.Map[Int,Seq[String]] =
// HashMap(2 -> List(sf), 3 -> List(sad), 4 -> List(dsvc, bbvv))
// you could also return something other than the actual length
words.groupBy(s => s.length 10)
// val res2: scala.collection.immutable.Map[Int,Seq[String]] =
// HashMap(14 -> List(dsvc, bbvv), 13 -> List(sad), 12 -> List(sf))
CodePudding user response:
words.groupBy(x => x.length())
.mapValues(x => x.head)
.view
.force
groupBy
creates a list, from which we take the first one. The last two lines are required because mapValues
creates an abstract view, not a concrete map.
You can stop at groupBy
if that serves your purpose.