将列表地图分割成地图列表的功能方式
问题描述:
我在这个问题上有点卡住了。我觉得自己在“思考倒退”,这让我感到困惑。我有Map[Long, Seq[String]]
,我想转换成Seq[Map[Long, String]]
。走向另一个方向是相当简单的,因为我们可以将元素分组在一起,但是,我不确定如何以功能方式将它们分开。将列表地图分割成地图列表的功能方式
所以,
val x = Map(1 -> List("a","b","c"), 2 -> List("d", "e"), 3 -> List("f"))
应该成为
List(Map(1 -> "a", 2 -> "d", 3 -> "f"), Map(1 -> "b", 2 -> "e"), Map(1 -> "c"))
我正沿着使用x.partition
然后迭代每个元组造成的线路在想,但我真的不知道我会分区:/
我正在写scala,但任何功能的答案是欢迎的(语言不可知的)。
答
在Haskell:
> import qualified Data.Map as M
> import Data.List
> m = M.fromList [(1,["a","b","c"]), (2,["d","e"]), (3,["f"])]
> map M.fromList . transpose . map (\(i,xs) -> map ((,) i) xs) . M.toList $ m
[fromList [(1,"a"),(2,"d"),(3,"f")],fromList [(1,"b"),(2,"e")],fromList [(1,"c")]]
M.toList
和M.fromList
转换的地图关联配对,和背部的列表。
map ((,) i) xs
与[(i,x) | x<-xs]
相同,将(i,...)
添加到每个元素。
transpose
在列表列表中交换“行”和“列”,类似于矩阵换位。
+0
我非常喜欢这个解决方案。谢谢! – puzzlement
答
在斯卡拉:
val result = x.toList
.flatMap { case (k, vs) => vs.zipWithIndex.map { case (v, i) => (i, k, v) } } // flatten and add indices to inner lists
.groupBy(_._1) // group by index
.toList.sortBy(_._1).map(_._2) // can be replaced with .values if order isn't important
.map(_.map { case (_, k, v) => (k, v) }.toMap) // remove indices
答
这是我在ocaml的答案(仅使用标准库):
module M = Map.Make(struct type t = int let compare = compare end)
let of_bindings b =
List.fold_right (fun (k, v) m -> M.add k v m) b M.empty
let splitmap m =
let split1 (k, v) (b1, b2) =
match v with
| [] -> (b1, b2)
| [x] -> ((k, x) :: b1, b2)
| h :: t -> ((k, h) :: b1, (k, t) :: b2)
in
let rec loop sofar m =
if M.cardinal m = 0 then
List.rev sofar
else
let (b1, b2) =
List.fold_right split1 (M.bindings m) ([], [])
in
let (ms, m') = (of_bindings b1, of_bindings b2) in
loop (ms :: sofar) m'
in
loop [] m
它为我的作品:
# let m = of_bindings [(1, ["a"; "b"; "c"]); (2, ["d"; "e"]); (3, ["f"])];;
val m : string list M.t = <abstr>
# let ms = splitmap m;;
val ms : string M.t list = [<abstr>; <abstr>; <abstr>]
# List.map M.bindings ms;;
- : (M.key * string) list list =
[[(1, "a"); (2, "d"); (3, "f")]; [(1, "b"); (2, "e")]; [(1, "c")]]
答
借用整齐transpose
方法从这SO answer,这是另一种方法来做到这一点:
def transpose[A](xs: List[List[A]]): List[List[A]] = xs.filter(_.nonEmpty) match {
case Nil => Nil
case ys: List[List[A]] => ys.map{ _.head }::transpose(ys.map{ _.tail })
}
transpose[(Int, String)](
x.toList.map{ case (k, v) => v.map((k, _)) }
).map{ _.toMap }
// Res1: List[scala.collection.immutable.Map[Int,String]] = List(
// Map(1 -> a, 2 -> d, 3 -> f), Map(1 -> b, 2 -> e), Map(1 -> c)
//)
我很好奇为什么你需要这个操作。这似乎有点令人惊讶。 – dfeuer