我有一个清单:
List[Any]("foo", 1, 2, "bar", 3, 4, 5)
我想用这种方式对它进行分组:
Map("foo" -> List(1,2), "bar" -> List(3,4,5))
我只能想象一个具有可变列表和变量的命令式风格的解决方案,但是解决此任务的正确方法是什么?
答案 0 :(得分:1)
考虑https://stackoverflow.com/a/21803339/3189923中定义的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))
答案 1 :(得分:1)
递归方式:
@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))
答案 2 :(得分:1)
简单。
如果列表中包含元素,请从tail
中取出所有整数,然后删除其余的整数,这些内容存储在rest
中。这就是span
的作用。然后将head
映射到ints
,然后针对rest
进行递归。
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]))
}
}
答案 3 :(得分:0)
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))