为什么带有收益的for循环累积到Map中而不​​是List中?

VSh*_*VSh 1 scala for-comprehension scala-collections

我有以下代码:

val dummy = Map(1 -> Map(2 -> 3.0,
                         4 -> 5.0),
                6 -> Map(7 -> 8.0))

val thisIsList = for (x <- dummy; y <- x._2.keys) yield s"(${x._1}, ${y})"
println(thisIsList)  // List((1, 2), (1, 4), (6, 7))

val thisIsMap = for (x <- dummy; y <- x._2.keys) yield new Tuple2(x._1, y)
println(thisIsMap)   // Map(1 -> 4, 6 -> 7) - this is not what I want    
Run Code Online (Sandbox Code Playgroud)

我希望第二个语句产生一个元组列表,但是它返回一个Map。我在这里找到了一个解释说明:生成一个元组序列而不是map来说明为什么返回Map,但是在这种情况下,我仍在努力寻找一种优雅的方法来返回元组列表。

Alu*_*dad 7

这是因为for编译器将理解语法转换为一系列方法调用的原因。mapflatMapwithFilter的目标是for理解力的排列。这是非常强大且通用的,因为它允许语法与任意类型一起使用。还有更多功能,例如CanBuildFrom 隐式,但本质上将a映射MapIterable[Tuple[A, B]]会产生Map[A, B]签名实际上已过载Map以提供此行为

具体来说,以下是您的原始代码

val thisIsMap = for (x <- dummy; y <- x._2.keys) yield new Tuple2(x._1, y)
println(thisIsMap)   // Map(1 -> 4, 6 -> 7) - this is not what I want
Run Code Online (Sandbox Code Playgroud)

翻译看起来像这样

val thisIsMap = dummy.flatMap { x =>
  x._2.keys.map { y =>
    (x._1, y)
  }
}
Run Code Online (Sandbox Code Playgroud)

看到这个小提琴

为了获得所需的列表,我们可以编写

val thisIsMap = (for (x <- dummy; y <- x._2.keys) yield (x._1, y)).toList
Run Code Online (Sandbox Code Playgroud)

但是,如果考虑到我们对for理解的了解,我们可以将其写得更加优雅:

val thisIsMap = for (x <- dummy.toList; y <- x._2.keys) yield (x._1, y)
Run Code Online (Sandbox Code Playgroud)

在上文中,我们通过推断对a的for理解List会产生a ,从而充分利用了混淆原始代码的行为List

但是,请注意,在理解之后,将源转换为aList与将结果映射转换为a的区别List

如果我们调用toListsource(dummyList((1,2), (1,4), (6,7)),则会得到结果,而如果对结果进行调用,则会得到结果,由于List((1,4), (6,7))显而易见的原因,请谨慎选择。