[英]flatmapping a nested Map in scala
Suppose I have val someMap = Map[String -> Map[String -> String]]
defined as such:假设我有
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") ) )
)
and I would like to flatten it to something that looks like我想把它压扁成看起来像的东西
List(
("a1","b1","c1"),("a1","b2","c2"),
("a2","b3","c3"),("a2","b4","c4"),
("a3","b5","c5"),("a3","b6","c6")
)
What is the most efficient way of doing this?这样做的最有效方法是什么? I was thinking about creating some helper function that processes each
(a_i -> Map(String,String))
key value pair and return我正在考虑创建一些辅助函数来处理每个
(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
}
then flatmap this function over someMap
.然后将该函数
someMap
映射到someMap
。 But this seems somewhat unnecessary to my novice scala eyes, so I was wondering if there was a more efficient way to parse this Map.但这对我的 scala 新手来说似乎有些不必要,所以我想知道是否有更有效的方法来解析这个 Map。
No need to create helper function just write nested lambda:无需创建辅助函数,只需编写嵌套的 lambda:
val result = someMap.flatMap { case (k, v) => v.map { case (k1, v1) => (k, k1, v1) } }
Or或者
val y = someMap.flatMap(x => x._2.map(y => (x._1, y._1, y._2)))
Since you're asking about efficiency, the most efficient yet functional approach I can think of is using foldLeft
and foldRight
.既然您问的是效率,我能想到的最有效但最实用的方法是使用
foldLeft
和foldRight
。
You need foldRight
since ::
constructs the immutable list in reverse.您需要
foldRight
因为::
反向构造不可变列表。
someMap.foldRight(List.empty[(String, String, String)]) { case ((a, m), acc) =>
m.foldRight(acc) {
case ((b, c), acc) => (a, b, c) :: acc
}
}
Here, assuming Map.iterator.reverse
is implemented efficiently, no intermediate collections are created.在这里,假设
Map.iterator.reverse
被有效地实现,则不会创建中间集合。
Alternatively, you can use foldLeft
and then reverse
the result:或者,您可以使用
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
This way a single intermediate List
is created, but you don't rely on the implementation of the reversed iterator ( foldLeft
uses forward iterator).这样就创建了一个中间
List
,但您不依赖于反向迭代器的实现( foldLeft
使用正向迭代器)。
Note: one liners, such as someMap.flatMap(x => x._2.map(y => (x._1, y._1, y._2)))
are less efficient, as, in addition to the temporary buffer to hold intermediate results of flatMap
, they create and discard additional intermediate collections for each inner map
.注意:一种衬垫,例如
someMap.flatMap(x => x._2.map(y => (x._1, y._1, y._2)))
效率较低,因为除了临时缓冲区为了保存flatMap
中间结果,它们为每个内部map
创建和丢弃额外的中间集合。
UPD UPD
Since there seems to be some confusion, I'll clarify what I mean.由于似乎有些混乱,我将澄清我的意思。 Here is an implementation of
map
, flatMap
, foldLeft
and foldRight
from TraversibleLike
:这是来自
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))
It's clear that map
and flatMap
create intermediate buffer using corresponding builder
, while foldLeft
and foldRight
reuse the same user-supplied accumulator object, and only use iterators.很明显,
map
和flatMap
使用相应的builder
创建中间缓冲区,而foldLeft
和foldRight
重用相同的用户提供的累加器对象,并且只使用迭代器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.