[英]flatmapping a nested Map in scala
假设我有val someMap = Map[String -> Map[String -> String]]
定义如下:
val someMap =
Map(
("a1" -> Map( ("b1" -> "c1"), ("b2" -> "c2") ) ),
("a2" -> Map( ("b3" -> "c3"), ("b4" -> "c4") ) ),
("a3" -> Map( ("b5" -> "c5"), ("b6" -> "c6") ) )
)
我想把它压扁成看起来像的东西
List(
("a1","b1","c1"),("a1","b2","c2"),
("a2","b3","c3"),("a2","b4","c4"),
("a3","b5","c5"),("a3","b6","c6")
)
这样做的最有效方法是什么? 我正在考虑创建一些辅助函数来处理每个(a_i -> Map(String,String))
键值对并返回
def helper(key: String, values: Map[String -> String]): (String,String,String)
= {val sublist = values.map(x => (key,x._1,x._2))
return sublist
}
然后将该函数someMap
映射到someMap
。 但这对我的 scala 新手来说似乎有些不必要,所以我想知道是否有更有效的方法来解析这个 Map。
无需创建辅助函数,只需编写嵌套的 lambda:
val result = someMap.flatMap { case (k, v) => v.map { case (k1, v1) => (k, k1, v1) } }
或者
val y = someMap.flatMap(x => x._2.map(y => (x._1, y._1, y._2)))
既然您问的是效率,我能想到的最有效但最实用的方法是使用foldLeft
和foldRight
。
您需要foldRight
因为::
反向构造不可变列表。
someMap.foldRight(List.empty[(String, String, String)]) { case ((a, m), acc) =>
m.foldRight(acc) {
case ((b, c), acc) => (a, b, c) :: acc
}
}
在这里,假设Map.iterator.reverse
被有效地实现,则不会创建中间集合。
或者,您可以使用foldLeft
然后reverse
结果:
someMap.foldLeft(List.empty[(String, String, String)]) { case (acc, (a, m)) =>
m.foldLeft(acc) {
case (acc, (b, c)) => (a, b, c) :: acc
}
}.reverse
这样就创建了一个中间List
,但您不依赖于反向迭代器的实现( foldLeft
使用正向迭代器)。
注意:一种衬垫,例如someMap.flatMap(x => x._2.map(y => (x._1, y._1, y._2)))
效率较低,因为除了临时缓冲区为了保存flatMap
中间结果,它们为每个内部map
创建和丢弃额外的中间集合。
UPD
由于似乎有些混乱,我将澄清我的意思。 这是来自TraversibleLike
的map
、 flatMap
、 foldLeft
和foldRight
的实现:
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
def builder = { // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
val b = bf(repr)
b.sizeHint(this)
b
}
val b = builder
for (x <- this) b += f(x)
b.result
}
def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
def builder = bf(repr) // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
val b = builder
for (x <- this) b ++= f(x).seq
b.result
}
def foldLeft[B](z: B)(op: (B, A) => B): B = {
var result = z
this foreach (x => result = op(result, x))
result
}
def foldRight[B](z: B)(op: (A, B) => B): B =
reversed.foldLeft(z)((x, y) => op(y, x))
很明显, map
和flatMap
使用相应的builder
创建中间缓冲区,而foldLeft
和foldRight
重用相同的用户提供的累加器对象,并且只使用迭代器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.