什么是创建列表地图的更实用的方法?

时间:2013-11-19 11:32:13

标签: scala

我有这个工作代码在String中的字符和包含索引的List之间创建Map。

scala> "Lollipop".zipWithIndex.foldLeft(Map[Char, List[Int]]())((acc, t) => acc + (t._1 -> (acc.getOrElse(t._1, List[Int]()) :+ t._2)))
res122: scala.collection.immutable.Map[Char,List[Int]] = Map(i -> List(4), L -> List(0), l -> List(2, 3), p -> List(5, 7), o -> List(1, 6))

acc.getOrElse的使用看起来势在必行。 是否有更多功能性方法可以隐藏用户?

2 个答案:

答案 0 :(得分:5)

for {
  (c, l) <- "Lollipop".zipWithIndex.groupBy{ _._1 }
} yield c -> l.map{ _._2 }
// Map(i -> Vector(4), L -> Vector(0), l -> Vector(2, 3), p -> Vector(5, 7), o -> Vector(1, 6))

groupBy{ _._1 }之后,您将获得Map[Char, Seq[(Char, Int)]]。因此,您必须使用(Char, Int)Int将对p => p._2转换为_._2

您可以像这样使用mapValues

"Lollipop".zipWithIndex.groupBy{ _._1 }.mapValues{ _.map{_._2} }

mapValues会创建一个惰性集合,因此如果按键多次访问同一元素,则可能会出现性能问题。

答案 1 :(得分:2)

替代方法是使用地图的默认值(重写代码稍微更明确):

val empty = Map.empty[Char, List[Int]].withDefaultValue(List.empty)
"Lollipop".zipWithIndex.foldLeft(empty) {
  case (acc, (char, position)) => {
    val positions = acc(char) :+ position
    acc + (char -> positions)
  } 
}