地图中的flatMap如何在scala中运行?

时间:2016-01-29 17:01:31

标签: scala dictionary flatmap

这是我的代码

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 comprehension a的屈服值更改为(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))

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

2 个答案:

答案 0 :(得分:2)

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

如果您获得了Map作为结果,那么您将映射到Map并提供二进制元组。所以编译器会搜索一个CanBuildFrom - 实例,它可以处理它。

为了找到这样的实例,编译器在不同的地方查找,例如当前范围,调用方法的类及其伴随对象。 在这种情况下,它将在canBuildFrom的伴随对象中找到一个名为Map的隐式字段,该字段是合适的,可用于构建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)

然而,这将:

v1 = null;

答案 1 :(得分:0)

要添加到@dth,如果需要列表,可以执行以下操作:

class foo:

    the_int = 0

    def __init__(self, i):
        self.bar = i

one, two = foo(5), foo(10)
ar = array([one, two])

int_array = ar[0:2].the_int

#I want int_array = [5, 10]

此处地图函数适用于惰性val l = Map(1->2,3->4).view.map( ... ).toList ,其输出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)) 使地图输出一个覆盖重复键的Map(并进行额外的和不必要的工作)。