【问题标题】:Understanding the Scala Map object when mapping to the head of a list映射到列表头部时理解 Scala Map 对象
【发布时间】:2017-11-06 13:50:24
【问题描述】:

您好,我有以下数据,想将其映射到第二个参数中的第一项。所以对于:

1 -> List((1,11))
1 -> List((1,1), (1,111))

我想要:

(1,11)
(1,1)

当此数据在 RDD 中时,我可以执行以下操作:

scala> val m = sc.parallelize(Seq(11 -> List((1,11)), 1 -> List((1,1),(1,111))))
m: org.apache.spark.rdd.RDD[(Int, List[(Int, Int)])] = ParallelCollectionRDD[198] at parallelize at <console>:47

scala> m.map(_._2.head).collect.foreach(println)
(1,11)
(1,1)

但是,当它位于 Map 对象中时(groupBy 的结果),我得到以下信息:

scala> val m = Map(11 -> List((1,11)), 1 -> List((1,1)))
m: scala.collection.immutable.Map[Int,List[(Int, Int)]] = Map(11 -> List((1,11)), 1 -> List((1,1), (1,111)))

scala> m.map(_._2.head)
res1: scala.collection.immutable.Map[Int,Int] = Map(1 -> 1)

当我映射到整个列表时,我得到了我期望的结果,但当我直接调用它时却没有

scala> m.map(_._2)
res2: scala.collection.immutable.Iterable[List[(Int, Int)]] = List(List((1,11)), List((1,1), (1,111)))

如果我执行以下任一操作,我也可以获得我想要的结果:

scala> m.map(_._2).map(_.head)
res4: scala.collection.immutable.Iterable[(Int, Int)] = List((1,11), (1,1))

scala> m.values.map(_.head)
res5: Iterable[(Int, Int)] = List((1,11), (1,1))

有人能解释一下这里发生了什么吗?

【问题讨论】:

  • 你也可以通过m.toSeq.map(_._2.head)得到想要的结果

标签: scala scala-collections implicit scala-implicits


【解决方案1】:

这有点棘手,取决于地图的隐式参数 CanBuildFrom。根据函数 f 的输出类型,它将能够构建一个结构或另一个(它将由隐式 CanBuildFrom 构建)。

m.map(_._2.head) // The passed function retrieves a pair (Int, Int)

有一个从 (A, A) 到 Map[A,A] 的隐式 CanBuildFrom,该对象被隐式传递给您的地图,这就是为什么在这种情况下返回的对象是 Map[Int, Int]

在另一种情况下,您有

m.map(_._2) // The passed function retrieves a List[(Int, Int)]

List[A] 的隐式 CanBuildFrom 将构建一个 Iterable[A],在这种情况下从 List[(Int, Int)] 到 Iterable[(Int, Int)]

【讨论】:

    【解决方案2】:

    scala.collection.immutable.Map 上的映射操作会根据映射操作的返回类型而有所不同。

    当返回类型为Tuple2[T,P]的if时

    Map 操作的输出结果是另一个Map,其中元组_1 的第一个元素作为键,第二个元素_2 作为值。

    例如

    scala> m.map(_ => 10 -> 1)
    res14: scala.collection.immutable.Map[Int,Int] = Map(10 -> 1) // note the return type is Map.
    

    当返回类型不是 Tuple2 时

    当返回类型不是 Tuple2 时,映射操作的输出是一个列表。

    scala> m.map(_ => 10 )
    res15: scala.collection.immutable.Iterable[Int] = List(10, 10) // note that the return type now is a List.
    

    根据上述既定事实,对于值Map(11 -&gt; List((1,11)), 1 -&gt; List((1,1)))Map,操作m.map(_._2.head) 产生Tuple2 值(1, 11)(1,1)。由于每个 Tuple2 项的第一个值 (_1) 是 1(即每个值的键是 1),(1,1) 会覆盖 (1,11),我们最终会得到单个值 (1,1)

    在其他情况下,映射操作不返回 Tuple2 的类型,因此它会导致 List 类型而不是 Maptypes,因此区别在于结果。

    【讨论】:

      猜你喜欢
      • 2015-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-25
      • 1970-01-01
      • 1970-01-01
      • 2019-12-06
      • 1970-01-01
      相关资源
      最近更新 更多