如何在scala的映射函数中使用if-to-filter?

如何在scala的映射函数中使用if-to-filter?,scala,collections,apache-spark,flatmap,Scala,Collections,Apache Spark,Flatmap,我有一个hadoopFiles对象,它是从sc.newAPIHadoopFile生成的 scala> hadoopFiles res1: org.apache.spark.rdd.RDD[(org.apache.hadoop.io.LongWritable, org.apache.hadoop.io.Text)] = UnionRDD[64] at union at <console>:24 但是,如果我删除if(pair.length==2)部分,它将正常工作: scala

我有一个hadoopFiles对象,它是从
sc.newAPIHadoopFile
生成的

scala> hadoopFiles
res1: org.apache.spark.rdd.RDD[(org.apache.hadoop.io.LongWritable, org.apache.hadoop.io.Text)] = UnionRDD[64] at union at <console>:24
但是,如果我删除
if(pair.length==2)
部分,它将正常工作:

scala>     val rowRDD = hadoopFiles.map(line =>
     |           line._2.toString.split("\\^") map {
     |             field => {
     |               var pair = field.split("=", 2)
     |               (pair(0) -> pair(1))
     |             }
     |           } toMap
     |         ).map(kvs => Row(kvs("uuid"), kvs("ip"), kvs("plt").trim))
warning: there was one feature warning; re-run with -feature for details
rowRDD: org.apache.spark.rdd.RDD[org.apache.spark.sql.catalyst.expressions.Row] = MappedRDD[66] at map at <console>:33

要在集合上映射并仅保留部分映射元素,可以使用
flatMap
flatMap
采用一个返回集合的函数,例如实例
选项
。现在,
if
表达式需要有一个
else
部分,该部分返回一个空的
选项,即
None

scala> val rowRDD = hadoopFiles.map(line =>
     |           line._2.toString.split("\\^") flatMap {
     |             field => {
     |               var pair = field.split("=", 2)
     |               if (pair.length == 2)
     |                 Some(pair(0) -> pair(1))
     |               else
     |                 None
     |             }
     |           } toMap
     |         ).map(kvs => Row(kvs("uuid"), kvs("ip"), kvs("plt").trim))

要在集合上映射并仅保留部分映射元素,可以使用
flatMap
flatMap
采用一个返回集合的函数,例如实例
选项
。现在,
if
表达式需要有一个
else
部分,该部分返回一个空的
选项,即
None

scala> val rowRDD = hadoopFiles.map(line =>
     |           line._2.toString.split("\\^") flatMap {
     |             field => {
     |               var pair = field.split("=", 2)
     |               if (pair.length == 2)
     |                 Some(pair(0) -> pair(1))
     |               else
     |                 None
     |             }
     |           } toMap
     |         ).map(kvs => Row(kvs("uuid"), kvs("ip"), kvs("plt").trim))

您可以使用
收集

val res = "1=a^2=b^3".split("\\^") collect {
  _.split("=", 2) match {
    case Array(a, b) => a -> b
  }
} toMap

println(res) // Map(1 -> a, 2 -> b)
在您的特殊情况下,会发生以下情况:

case class Row(uuid: String, ip: String, plt: String)
val hadoopFiles = List(("", "uuid=a^ip=b^plt"))

val rowRDD = hadoopFiles.map(line =>
  line._2.toString.split("\\^") map {
    field =>
      {
        var pair = field.split("=", 2)
        val res = if (pair.length == 2)
          (pair(0) -> pair(1))
        res  // res: Any (common super class for (String, String)
             // which is Tuple2 and Unit (result for case when 
             // pair.length != 2)
      }
  } /* <<< returns Array[Any] */ /*toMap*/ ) 
  //.map(kvs => Row(kvs("uuid"), kvs("ip"), kvs("plt").trim))
对于
数组[Any]
,在当前上下文中没有从
Any
(T,U)
的隐式转换。因此,您的代码失败。 如果您添加了其他备选方案:

  val rowRDD = hadoopFiles.map(line =>
    (line._2.toString.split("\\^") map {
      field =>
        {
          var pair = field.split("=", 2)
          val res = if (pair.length == 2)
            (pair(0) -> pair(1))
          else ("" -> "") // dummy, just for demo
          res // res: (String, String)
        }
    } toMap) withDefaultValue ("") 
           /*withDefaultValue just to avoid Exception for this demo*/ )
    .map(kvs => Row(kvs("uuid"), kvs("ip"), kvs("plt").trim))

  println(rowRDD) // List(Row(a,b,))

这里的结果将是数组[(字符串,字符串)],并且有一个从
(字符串,字符串)
(T,U)
的隐式转换。因此,代码可以编译并工作。

您可以使用
收集

val res = "1=a^2=b^3".split("\\^") collect {
  _.split("=", 2) match {
    case Array(a, b) => a -> b
  }
} toMap

println(res) // Map(1 -> a, 2 -> b)
在您的特殊情况下,会发生以下情况:

case class Row(uuid: String, ip: String, plt: String)
val hadoopFiles = List(("", "uuid=a^ip=b^plt"))

val rowRDD = hadoopFiles.map(line =>
  line._2.toString.split("\\^") map {
    field =>
      {
        var pair = field.split("=", 2)
        val res = if (pair.length == 2)
          (pair(0) -> pair(1))
        res  // res: Any (common super class for (String, String)
             // which is Tuple2 and Unit (result for case when 
             // pair.length != 2)
      }
  } /* <<< returns Array[Any] */ /*toMap*/ ) 
  //.map(kvs => Row(kvs("uuid"), kvs("ip"), kvs("plt").trim))
对于
数组[Any]
,在当前上下文中没有从
Any
(T,U)
的隐式转换。因此,您的代码失败。 如果您添加了其他备选方案:

  val rowRDD = hadoopFiles.map(line =>
    (line._2.toString.split("\\^") map {
      field =>
        {
          var pair = field.split("=", 2)
          val res = if (pair.length == 2)
            (pair(0) -> pair(1))
          else ("" -> "") // dummy, just for demo
          res // res: (String, String)
        }
    } toMap) withDefaultValue ("") 
           /*withDefaultValue just to avoid Exception for this demo*/ )
    .map(kvs => Row(kvs("uuid"), kvs("ip"), kvs("plt").trim))

  println(rowRDD) // List(Row(a,b,))

这里的结果将是数组[(字符串,字符串)],并且有一个从
(字符串,字符串)
(T,U)
的隐式转换。因此代码可以编译并运行。

如果
pair.length!=2
。你也为那个案子提供了一些证据,把它过滤掉就行了。我只寻找由两部分组成的键值对@SarveshKumarSinghWhat if
pair.length!=2
。你也为那个案子提供了一些证据,把它过滤掉就行了。我只寻找由两部分组成的键值对@Sarveshkumarsinght也就是说,如果我的行看起来像'1=a^2=b^3',上面的flatMap函数将只返回(1->a)和(2->b)?我对scala和Spark都是新手,
Some
None
关键字在这里与
flatMap
交互时起什么作用?为什么不使用
map
函数呢?它抛出了另一个错误:错误:value flatmap不是数组[String]
的成员,有些
None
不是关键字。它们是
选项
的子类,这是一个容器,可以有零个元素(
)或一个元素(
一些
)。当修改为
平面图
时,这正是我所期望的。感谢您的详细解释:]也就是说,如果我的行看起来像'1=a^2=b^3',上面的flatMap函数将只返回(1->a)和(2->b)?我对scala和Spark都是新手,
Some
None
关键字在这里与
flatMap
交互时起什么作用?为什么不使用
map
函数呢?它抛出了另一个错误:错误:value flatmap不是数组[String]
的成员,有些
None
不是关键字。它们是
选项
的子类,这是一个容器,可以有零个元素(
)或一个元素(
一些
)。当修改为
平面图
时,这正是我所期望的。感谢您的详细解释:]