I thought that Scala construct map(f).flatten
was equivalent to flatMap(f)
. But with this example, it is not the case. I wonder what is the role of the case class in it. If I use integers, both are equivalent. But in my case, I cannot.
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
Yields
Set((CTest(0),3), (CTest(1), 2))
whereas
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
yields
Set((CTest(0),0), (CTest(0),3), (CTest(1),0), (CTest(1),2))
Any idea why?
This happens due to intermediate data structures.
I'll take simple version of your example.
val m = Map(CTest(0) -> List(0, 3), CTest(1) -> List(0, 2))
When using flatMap
you directly create a 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)
In here, due to the uniqueness of the keys of Map
, (CTest(0), 0)
and (CTest(1), 0)
will be dropped from the result. when you flatMap
it over set, you will get a Set
of Tuples
which were in the Map
.
In your second example, you map and flatten.
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))
There isn't any Map
or another uniqueness preserved data structure created in the middle of the process. So values are not dropped.