Home > OS >  How to groupBy length of Strings on a collection of Strings?
How to groupBy length of Strings on a collection of Strings?

Time:11-05

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.

  • Related