【问题标题】:Error: type mismatch flatMap错误:类型不匹配 flatMap
【发布时间】:2019-03-04 14:21:37
【问题描述】:

我是 spark 编程和 scala 的新手,我无法理解 map 和 flatMap 之间的区别。 我尝试了下面的代码,因为我希望两者都能工作,但出错了。

scala> val b = List("1","2", "4", "5")
b: List[String] = List(1, 2, 4, 5)

scala> b.map(x => (x,1))
res2: List[(String, Int)] = List((1,1), (2,1), (4,1), (5,1))

scala> b.flatMap(x => (x,1))
<console>:28: error: type mismatch;
 found   : (String, Int)
 required: scala.collection.GenTraversableOnce[?]
              b.flatMap(x => (x,1))

根据我的理解,平面图将 Rdd 放入 String/Int Rdd 的集合中。 我在想,在这种情况下,两者都应该没有任何错误。请让我知道我在哪里犯了错误。

谢谢

【问题讨论】:

    标签: scala apache-spark


    【解决方案1】:

    你需要看看签名是如何定义这些方法的:

    def map[U: ClassTag](f: T => U): RDD[U]
    

    map 将一个函数从T 类型转换为U 类型并返回一个RDD[U]

    另一方面,flatMap

    def flatMap[U: ClassTag](f: T => TraversableOnce[U]): RDD[U]
    

    期望将类型T 转换为TraversableOnce[U] 的函数,这是Tuple2 未实现的特征,并返回RDD[U]。通常,当您想要展平集合集合时使用flatMap,即如果您有一个RDD[List[List[Int]],并且您想生成一个RDD[List[Int]],您可以使用identity 对其进行平面映射。

    【讨论】:

    • 感谢@YuvalItzchakov 的帮助,如果我在列表(1,2,4 ..)上使用平面图时理解正确,它只是一个集合而不是集合的集合,所以它显示了错误
    • @Anaadih 是的,没错。投影需要 TraversableOnce[U],它是一个集合类型。
    【解决方案2】:

    ma​​p(func) 返回一个新的分布式数据集,通过函数 func 传递源的每个元素形成。

    flatMap(func) 类似于 map,但每个输入项可以映射到 0 个或多个输出项(因此 func 应该返回一个 Seq 而不是单个项)。

    以下示例可能会有所帮助。

            scala> val b = List("1", "2", "4", "5")
            b: List[String] = List(1, 2, 4, 5)
    
            scala> b.map(x=>Set(x,1))
            res69: List[scala.collection.immutable.Set[Any]] =     
            List(Set(1, 1), Set(2, 1), Set(4, 1), Set(5, 1))
    
            scala> b.flatMap(x=>Set(x,1))
            res70: List[Any] = List(1, 1, 2, 1, 4, 1, 5, 1)
    
            scala> b.flatMap(x=>List(x,1))
            res71: List[Any] = List(1, 1, 2, 1, 4, 1, 5, 1)
    
            scala> b.flatMap(x=>List(x+1))
            res75: scala.collection.immutable.Set[String] = List(11, 21, 41, 51) // concat
    
    
    
    
            scala> val x = sc.parallelize(List("aa bb cc dd",  "ee ff gg hh"), 2)
    
            scala> val y = x.map(x => x.split(" ")) // split(" ") returns an array of words
            scala> y.collect
            res0: Array[Array[String]] = Array(Array(aa, bb, cc, dd), Array(ee, ff, gg, hh))
    
            scala> val y = x.flatMap(x => x.split(" "))
            scala> y.collect
            res1: Array[String] = Array(aa, bb, cc, dd, ee, ff, gg, hh)
    

    【讨论】:

      【解决方案3】:

      Map 操作返回类型为 U 其中 flatMap 返回类型为 TraversableOnce[U](表示集合)

      val b = List("1", "2", "4", "5")
      val mapRDD = b.map { input => (input, 1) }
      mapRDD.foreach(f => println(f._1 + "  " + f._2))
      
      val flatmapRDD = b.flatMap { input => List((input, 1)) }
      flatmapRDD.foreach(f => println(f._1 + "  " + f._2))
      

      【讨论】:

      • 简单明了。这应该是正确的答案。
      【解决方案4】:

      map 进行一对一的转换,而 flatMap 将列表列表转换为单个列表:

      scala> val b = List(List(1,2,3), List(4,5,6), List(7,8,90))
      b: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 90))
      
      scala> b.map(x => (x,1))
      res1: List[(List[Int], Int)] = List((List(1, 2, 3),1), (List(4, 5, 6),1), (List(7, 8, 90),1))
      
      scala> b.flatMap(x => x)
      res2: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 90)
      

      此外,如果您有 Options 的列表,flatMap 对于过滤掉 None 值很有用:

      scala> val c = List(Some(1), Some(2), None, Some(3), Some(4), None)
      c: List[Option[Int]] = List(Some(1), Some(2), None, Some(3), Some(4), None)
      
      scala> c.flatMap(x => x)
      res3: List[Int] = List(1, 2, 3, 4)
      

      【讨论】:

      • 感谢@anthonybell 提供信息,但在我的地图和平面地图的情况下,我使用了一个列表,但我仍然遇到错误。
      • flatMap 期望列表中的每个“项目”也是一个列表。如果你写的是b.flatMap(x =&gt; List((x,1))),它会和map一样工作。
      猜你喜欢
      • 1970-01-01
      • 2013-01-16
      • 2014-02-05
      • 2018-06-08
      • 2012-02-16
      • 2012-02-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多