8

(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

4

2 回答 2

19

使用 Scala 2.8.0:

list.groupBy(_.length)

没有比这更简单的了!

于 2009-07-31T04:21:23.310 回答
7

如果你不介意糟糕的表现:

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: _*)

问题是对于每个不同的长度都会再次读取列表。

现在,关于您的版本的丑陋,也许这会有所帮助:

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

更好的?它仍然不是很好,因为你得到了两次长度。这个没有这个问题,但是稍微丑了点:

list.foldLeft(Map[Long, List[String]]()) {
  (m, s) => val length = s.length; m(length) = s :: m.getOrElse(length, Nil)
}
于 2009-07-30T23:37:15.143 回答