我有这个工作代码在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
的使用看起来势在必行。
是否有更多功能性方法可以隐藏用户?
答案 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)
}
}