Reputation:
(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
Upvotes: 8
Views: 1932
Reputation: 11596
With Scala 2.8.0:
list.groupBy(_.length)
It can not get any simpler than that!
Upvotes: 19
Reputation: 297195
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)
}
Upvotes: 7