scala 地图展平和平面地图不等价

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20215518/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:53:50  来源:igfitidea点击:

Map flatten and flatmap not equivalent

scaladictionarycase-class

提问by Mika?l Mayer

I thought that Scala construct map(f).flattenwas 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.

我认为Scala 构造map(f).flatten等效于flatMap(f). 但在这个例子中,情况并非如此。我想知道case类在其中的作用是什么。如果我使用整数,则两者是等效的。但就我而言,我不能。

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?

知道为什么吗?

采纳答案by chemikadze

Take a look at implementation of flatMap:

看一下实现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
}

Result of flatMapdepends on original collection type and result type of function f. In first example you generate sequence of tuples from map, so that compiler picks implementation like CanBuildFrom[Map[A, B], (C, D), Map[C, D]], which provides builder for Map, that causes overwriting of same keys.

结果flatMap取决于函数的原始集合类型和结果类型f。在第一个示例中,您从 map 生成元组序列,以便编译器选择类似 的实现CanBuildFrom[Map[A, B], (C, D), Map[C, D]],它为 提供构建器Map,这会导致覆盖相同的键。

You can directly convert map to plain iterable, that will yield result you want:

您可以直接将地图转换为普通可迭代的,这将产生您想要的结果:

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

回答by tiran

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 flatMapyou directly create a Map[CTest, Int]

使用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)

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 flatMapit over set, you will get a Setof Tupleswhich were in the Map.

在这里,由于Map,(CTest(0), 0)和的键的唯一性,(CTest(1), 0)将从结果中删除。当你flatMap过来设置,你会得到SetTuples,其均在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 Mapor another uniqueness preserved data structure created in the middle of the process. So values are not dropped.

Map在过程中间没有创建任何或其他唯一性保留数据结构。所以值不会被丢弃。