【发布时间】:2019-12-20 13:29:01
【问题描述】:
我正在尝试使用 flatMap 和 map 的组合将下面的 Map[T,List[T]] 转换为 List[T]
val numMap = Map(1 -> List(2) , 3 -> List(2,4))
val numPairs = numMap.flatMap{ case (n, nlist) => nlist.map (x => (x,n) ) }
结果是Map
res12: scala.collection.immutable.Map[Int,Int] = Map(2 -> 3, 4 -> 3)
而不是预期的List
List((2,1), (2,3), (4,3))
虽然我可以通过一系列map 操作达到预期结果
scala> numMap.map{ case (n, nlist) => nlist.map (x => (x,n) ).toList }.flatten
res20: scala.collection.immutable.Iterable[(Int, Int)] = List((2,1), (2,3), (4,3))
我想了解为什么使用 flatMap 失败。
【问题讨论】:
-
因为,对于 Map 有两种
flatMap的变体,如果函数的返回类型是另一个集合,一个会返回另一个 Map元组。有两种选择,一种是通过类型参数numMap.flatMap[(Int, Int)] { ... }强制另一种重载,但是这个将返回 Iterable[(Int, Int)] 而不是 List。其他替代方法是使用 Iterator,numMap.iterator.flatMap { ... }.toList. -
对一个单子的
flatMap操作应该返回另一个相同类型的单子,所以真正的问题是为什么Map.flatMap不返回另一个Map! -
@LuisMiguelMejíaSuárez 如果总是这样,为什么以下返回列表
scala> Map(2 -> 3, 4 -> 3).flatMap { case (k,v) => List(k,v) } res29: scala.collection.immutable.Iterable[Int] = List(2, 3, 4, 3) -
@Benny 我不确定你到底在问什么,它不能是 Map 因为那不是 的 List元组,即具有两个元素的 Ints 的 List。这就是为什么你得到一个 Ints 的 Iterable (不是一个 List) - 你可能会说,你在那里看到一个 List,但那是 runtime
class。变量的statictype是Iterable。对于编译器,只有types存在,您不能安全地将其用作List,只能用作Iterable。 -
@LuisMiguelMejíaSuárez 谢谢!接受的答案澄清了地图的两种变体之间的区别。你是对的,我被运行时类
List误导了,但是我不知道运行时类可以不同于静态类型。我在哪里可以找到有关此的更多信息?