我认为Scala construct map(f).flatten
was equivalent to flatMap(f)
。但是通过这个例子,情况并非如此。我想知道案例类的作用是什么。如果我使用整数,两者都是等价的。但就我而言,我不能。
case class CTest(v: Int)
val s = Set(Map(CTest(0) -> List(0, 3), CTest(1) -> List(0, 2)))
val possibilities = s flatMap { m =>
val mapping = m flatMap {
case (label, destNodes) => destNodes map {
case nodes => (label, nodes) }
}
mapping
}
possibilities
产量
Set((CTest(0),3), (CTest(1), 2))
,而
case class CTest(v: Int)
val s = Set(Map(CTest(0) -> List(0, 3), CTest(1) -> List(0, 2)))
val possibilities = s flatMap { m =>
val mapping = m map {
case (label, destNodes) => destNodes map {
case nodes => (label, nodes) }
}
mapping.flatten
}
possibilities
产量
Set((CTest(0),0), (CTest(0),3), (CTest(1),0), (CTest(1),2))
知道为什么吗?
答案 0 :(得分:10)
这是由于中间数据结构而发生的。
我将采用你的例子的简单版本。
val m = Map(CTest(0) -> List(0, 3), CTest(1) -> List(0, 2))
使用flatMap
时,您可以直接创建Map[CTest, Int]
scala> m flatMap {
| case (label, destNodes) => destNodes map {
| case nodes => (label, nodes) }
| }
res3: scala.collection.immutable.Map[CTest,Int] = Map(CTest(0) -> 3, CTest(1) -> 2)
在此处,由于Map
键的唯一性,(CTest(0), 0)
和(CTest(1), 0)
将从结果中删除。当您flatMap
过度设置时,您将获得Set
中的Tuples
Map
。
在第二个示例中,您将映射并展平。
val mapping = m map {
| case (label, destNodes) => destNodes map {
| case nodes => (label, nodes) }
| }
mapping: scala.collection.immutable.Iterable[List[(CTest, Int)]] = List(List((CTest(0),0), (CTest(0),3)), List((CTest(1),0), (CTest(1),2)))
mapping.flatten
res4: scala.collection.immutable.Iterable[(CTest, Int)] = List((CTest(0),0), (CTest(0),3), (CTest(1),0), (CTest(1),2))
在流程中间没有创建任何Map
或其他唯一性保留数据结构。所以价值不会下降。
答案 1 :(得分:7)
了解flatMap
的实施情况:
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
}
flatMap
的结果取决于函数f
的原始集合类型和结果类型。在第一个示例中,您从map生成元组序列,以便编译器选择CanBuildFrom[Map[A, B], (C, D), Map[C, D]]
之类的实现,它为Map
提供构建器,导致覆盖相同的键。
您可以直接将map转换为plain iterable,这将产生您想要的结果:
case class CTest(v: Int)
val s = Set(Map(CTest(0) -> List(0, 3), CTest(1) -> List(0, 2)))
val possibilities = s flatMap { m =>
val mapping = m.toIterable.flatMap {
case (label, destNodes) => destNodes map {
case nodes => (label, nodes) }
}
mapping
}
possibilities