Scala 按字符串int*模式对列表元素进行分组
我有一份清单:Scala 按字符串int*模式对列表元素进行分组,scala,scala-collections,Scala,Scala Collections,我有一份清单: List[Any]("foo", 1, 2, "bar", 3, 4, 5) 我想以这种方式对其元素进行分组: Map("foo" -> List(1,2), "bar" -> List(3,4,5)) 我只能想象一个带有可变列表和变量的命令式解决方案,但解决此任务的正确方法是什么 def toMap(seq: Seq[Any]) = { val (result, _) = seq.foldRight((Map.empty[String, Seq[Int]
List[Any]("foo", 1, 2, "bar", 3, 4, 5)
我想以这种方式对其元素进行分组:
Map("foo" -> List(1,2), "bar" -> List(3,4,5))
我只能想象一个带有可变列表和变量的命令式解决方案,但解决此任务的正确方法是什么
def toMap(seq: Seq[Any]) = {
val (result, _) = seq.foldRight((Map.empty[String, Seq[Int]], "")) {
(el, acc) =>
val (map, str) = acc
el match {
case s: String =>
(map, s)
case number: Int =>
val el = map.getOrElse(str, Seq[Int]())
(map + (str -> (number +: el)), str)
}
}
result
}
==测试==
scala> val list = List[Any]("foo", 1, 2, "bar", 3, 4, 5)
list: List[Any] = List(foo, 1, 2, bar, 3, 4, 5)
scala> toMap(list)
res3: scala.collection.immutable.Map[String,Seq[Int]] = Map(foo -> List(2, 1), bar -> List(5, 4, 3))
考虑中定义的
multiSpan
;那么
val a = List[Any]("foo", 1, 2, "bar", 3, 4, 5)
我们有
val b = a.multiSpan(_.isInstanceOf[String])
b: List[List[Any]] = List(List(foo, 1, 2), List(bar, 3, 4, 5))
诸如此类
b.map { l => (l.head, l.tail) }.toMap
res: Map(foo -> List(1, 2), bar -> List(3, 4, 5))
递归方式:
@tailrec
def toMap(list:List[Any], acc:Map[String,List[Int]] = Map()):Map[String,List[Int]] = list match {
case Nil => acc
case List(key:String, _*) => {
val values = list.drop(1).takeWhile(_.isInstanceOf[Int]).map {case i:Int => i}
toMap(list.drop(1+values.size), acc + (key -> values))
}
}
似乎工作正常:
scala> toMap(list)
res0: Map[String,List[Any]] = Map(foo -> List(1, 2), bar -> List(3, 4, 5))
直截了当
如果列表中有元素,则从尾部
获取所有整数,并删除剩余的整数,该整数存储在rest
中。这就是span
所做的。然后将头部
映射到内部
并递归地为其余部分
执行此操作
def f(a: List[Any]): Map[String, List[Int]] = a match {
case Nil => Map.empty
case head :: tail => {
val (ints, rest) = tail.span(_.isInstanceOf[Int])
f(rest) + (head.asInstanceOf[String] -> ints.map(_.asInstanceOf[Int]))
}
}
我们的解决方案非常相似。不过,我建议您使用
span
,这样您可以同时上下。