Scala将Collection转换为按键映射的最佳方法是什么? (第二个变种)

时间:2009-07-30 22:12:12

标签: list scala map scala-collections

(这是this Q&A)的变体

说我有这个:

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

我想创建一个Map,其键是String的长度,值是具有该长度的所有字符串的Collection。换句话说,鉴于关于List,我们得到:

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

我写的代码是:

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

这很有效,但它给Daniel Spiewak提供给原始问题(上面提到的)的优雅答案增添了许多丑陋。

如何改进我的变体的解决方案?

谢谢! 肖恩

2 个答案:

答案 0 :(得分:19)

使用Scala 2.8.0:

list.groupBy(_.length)

它不能比那更简单!

答案 1 :(得分: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)
}