views:

528

answers:

3

(This is a variant to this Q&A)

Say I have this:

List( "foo", "bar", "spam" )

I want to create a Map for which the key is the length of the String and the value is a Collection of all the Strings that have that length. In other words, given the about List, we'd get:

Map( 3 -> List(foo, bar), 4 -> List(spam) )

The code I've written to do this is:

list.foldLeft(Map[Long, List[String]]()) {
  (m, s) => m(s.length) = s ::
     ( if ( m.contains(s.length) ) m(s.length)
       else Nil )
}

This works, but it adds a lot of ugliness to the elegant answer Daniel Spiewak provided to the original question (referenced above).

Any ideas how to improve the solution for my variant?

Thanks! Sean

+7  A: 

If you don't mind lousy performance:

val list = List( "foo", "bar", "spam" )
val keyValue = for (length <- list map (_ length) removeDuplicates;
                    strings = list filter (_.length == length)) 
               yield (length -> strings)
val map = Map(keyValue: _*)

The problem is that the list is read again for each different length.

Now, about the uglyness of your version, perhaps this helps:

list.foldLeft(Map[Long, List[String]]()) {
  (m, s) => m(s.length) = s :: m.getOrElse(s.length, Nil)
}

Better? It's still not quite good because you get the length twice. This one doesn't have this problem, but it's slightly uglier:

list.foldLeft(Map[Long, List[String]]()) {
  (m, s) => val length = s.length; m(length) = s :: m.getOrElse(length, Nil)
}
Daniel
I don't find the last variant ugly, if val length is shortened to val l. Single letter variables in scala are often used in scala in style similar to mathematic formulas, i.e. you declare the meaning of a placeholder variable, and then just use it. Because this leads to very short expressions (most often one liners), the short name which would be considered cryptic in other languages is not a problem in practice.
Palimondo
@Palimondo It's not the length that annoys me. I dislike breaking the computation in two statements. Unfortunately, Scala can't optimize `s.length` to reuse the value, as Haskell would.
Daniel
+11  A: 

With Scala 2.8.0:

list.groupBy(_.length)

It can not get any simpler than that!

Walter Chang
I think this is very elegant, but I don't understand why the sort is needed. Can you explain it? Thanks.
agilefall
@agilefall: you're right. sort is not needed. thanks!
Walter Chang
A: 

Thank you both, Daniel and Walter. I like both of those answers (one for pre Scala 2.8 and the other for Scala 2.8). I would vote both your answers up, but don't have the reputation yet.

Thanks again!

What happened to the "Sean Crotty" account? It has 41 reputation, mostly from the question itself.
Daniel
I used an anonymous account to ask the question as "Sean Crotty". Then I decided I should probably be a member of StackOverflow and am now scrotty. But my reputation points are stuck with the anonymous me - floating in the ether forever unclaimed. :)