Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.4k views
in Technique[技术] by (71.8m points)

scala - Map flatten and flatmap not equivalent

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...