【问题标题】:How flatMap in a Map works in scala?Map 中的 flatMap 如何在 scala 中工作?
【发布时间】:2016-01-29 17:01:31
【问题描述】:

这是我的代码

def testMap() = {
    val x = Map(
      1 -> Map(
        2 -> 3,
        3 -> 4
      ),
      5 -> Map(
        6 -> 7,
        7 -> 8
      )
    )

    for {
      (a, v) <- x
      (b, c) <- v
    } yield {
      a
    }
  }

上面的代码给出了

List(1, 1, 5, 5)

如果我将for理解a的yield值改为(a, b),结果是

Map(1 -> 3, 5 -> 7)

如果我把(a, b)改成(a, b, c),结果是

List((1,2,3), (1,3,4), (5,6,7), (5,7,8))

我的问题是,在这种理解中确定结果类型背后的机制是什么?

【问题讨论】:

  • 它尝试匹配原始类型。当你返回对时,你最终会得到一个地图,否则如果无法制作地图,那么你会得到一个列表。
  • 你能解释一下代码和编译器的行为吗?
  • 我以为我刚刚做到了 :) 如果您以 Map 开头并产生对,那么您最终会得到 Map。否则,你会得到一个List,无论你产生什么类型。究竟是什么还不清楚?
  • 如果要对代码进行脱糖,请参阅:stackoverflow.com/a/9892350/651140scala -print file.scala

标签: scala dictionary flatmap


【解决方案1】:

当您查看 API 文档以了解 map-Method 的详细信息时,您会发现它有第二个类型为 CanBuildFrom 的隐式参数。 CanBuildFrom from 的一个实例定义了在映射到某个其他集合并提供某种元素类型时如何构建某个集合。

如果你得到一个 Map 作为结果,你正在映射一个 Map 并提供二进制元组。所以编译器会搜索一个可以处理的CanBuildFrom-instance。

为了找到这样的实例,编译器会在不同的地方查找,例如当前范围,调用方法的类及其伴生对象。 在这种情况下,它将在Map 的伴随对象中找到一个名为canBuildFrom 的隐式字段,该字段是合适的并且可以用于构建Map 作为结果。因此它尝试将结果类型推断为Map,并在成功时使用此实例。

在您提供单个值或三元组的情况下,在 Map 的同伴中找到的实例不具有所需的类型,因此它会继续搜索继承树。它在Iterable 的伴随对象中找到它。他们允许构建任意元素类型的Iterable 的实例。所以编译器使用它。

那么为什么你会得到List?因为那恰好是那里使用的实现,所以类型系统只保证你是一个Iterable

如果您想获得Iterable 而不是Map,您可以显式提供CanBuildFrom 实例(仅当您直接调用map 和flatMap 时)或只强制返回类型。在那里您还会注意到,即使您获得了List,您也无法请求。

这行不通:

val l: List[Int] = Map(1->2).map(x=>3)

然而这会:

val l: Iterable[Int] = Map(1->2).map(x=>3)

【讨论】:

    【解决方案2】:

    要添加到@dth,如果你想要一个列表,你可以这样做:

    val l = Map(1->2,3->4).view.map( ... ).toList
    

    这里的map函数应用在一个惰性IterableView上,它也输出一个IterableView,实际的构造是由toList触发的。

    注意:另外,不使用view 可能会导致危险行为。示例:

    val m = Map(2->2,3->3)
    
    val l = m.map{ case (k,v) => (k/2,v) ).toList
    // List((1,3))
    
    val l = m.view.map{ case (k,v) => (k/2,v) ).toList
    // List((1,2), (1,3))
    

    在这里,省略.view 使地图输出一个覆盖重复键的地图(并执行额外和不必要的工作)。

    【讨论】:

      猜你喜欢
      • 2017-10-19
      • 2018-05-07
      • 1970-01-01
      • 2010-11-06
      • 1970-01-01
      • 1970-01-01
      • 2020-10-14
      • 1970-01-01
      • 2011-10-05
      相关资源
      最近更新 更多