如何将地图的键从String转换为Int?

时间:2017-04-28 21:55:17

标签: scala

这是我的初始RDD输出

scala> results
scala.collection.Map[String,Long] = Map(4.5 -> 1534824, 0.5 -> 239125, 3.0 -> 4291193, 3.5 -> 2200156, 2.0 -> 1430997, 1.5 -> 279252, 4.0 -> 5561926, 
rating -> 1, 1.0 -> 680732, 2.5 -> 883398, 5.0 -> 2898660)

我正在移除一个字符串Key以仅保留数字。

scala> val resultsInt = results.filterKeys(_ != "rating")
resultsInt: scala.collection.Map[String,Long] = Map(4.5 -> 1534824, 0.5 -> 239125, 3.0 -> 4291193, 3.5 -> 2200156, 2.0 -> 1430997, 1.5 -> 279252, 4.0 -> 5561926, 1.0 -> 680732, 2.5 -> 883398, 5.0 -> 2898660)

根据值对RDD进行排序,它给出了预期的输出,但是我希望在排序之前将键从String转换为int以获得一致的输出。

scala> val sortedOut2 = resultsInt.toSeq.sortBy(_._1)
sortedOut2: Seq[(String, Long)] = ArrayBuffer((0.5,239125), (1.0,680732), (1.5,279252), (2.0,1430997), (2.5,883398), (3.0,4291193), (3.5,2200156), (4.0,5561926), (4.5,1534824), (5.0,2898660))

我是Scala的新手,刚开始编写我的Spark程序。请告诉我一些转换Map对象密钥的见解。

5 个答案:

答案 0 :(得分:1)

根据您的示例输出,我想您的意思是将密钥转换为Double

val results: scala.collection.Map[String, Long] = Map(
  "4.5" -> 1534824, "0.5" -> 239125, "3.0" -> 4291193, "3.5" -> 2200156,
  "2.0" -> 1430997, "1.5" -> 279252, "4.0" -> 5561926, "rating" -> 1,
  "1.0" -> 680732, "2.5" -> 883398, "5.0" -> 2898660
)

results.filterKeys(_ != "rating").
  map{ case(k, v) => (k.toDouble, v) }.
  toSeq.sortBy(_._1)

res1: Seq[(Double, Long)] = ArrayBuffer((0.5,239125), (1.0,680732), (1.5,279252), (2.0,1430997),
   (2.5,883398), (3.0,4291193), (3.5,2200156), (4.0,5561926), (4.5,1534824), (5.0,2898660))

答案 1 :(得分:0)

要在不同类型之间进行映射,您只需使用地图Spark / Scala运算符。

您可以从此处查看语法 enter image description here

同样的方法可以与Spark和Scala一起使用。

答案 2 :(得分:0)

请参阅Scala - Convert keys from a Map to lower case?

方法应该类似,

case class row (id: String, value:String)

val rddData = sc.parallelize(Seq(row("1", "hello world"), row("2", "hello there")))

rddData.map{
     currentRow => (currentRow.id.toInt, currentRow.value)}
//scala> org.apache.spark.rdd.RDD[(Int, String)]

即使你没有为rdd的结构定义一个case类,你也可以使用类似Tuple2的东西,你可以写

currentRow._1.toInt // instead of currentRow.id.toInt

请研究铸造信息(从String转换为Int),还有几种方法可以解决这个问题

希望这有帮助!祝你好运:)

答案 3 :(得分:0)

如果您尝试过滤掉非数字的密钥,您可以执行以下操作:

import scala.util.{Try,Success,Failure}

(results map { case (k,v) => Try (k.toFloat) match {
  case Success(x) => Some((x,v))
  case Failure(_) => None
}}).flatten

res1: Iterable[(Float, Long)] = List((4.5,1534824), (0.5,239125), (3.0,4291193), (3.5,2200156), (2.0,1430997), (1.5,279252), (4.0,5561926), (1.0,680732), (2.5,883398), (5.0,2898660))

答案 4 :(得分:0)

RDD提取到Map是合法的,但它首先违背了使用Spark的目的。如果您正在大规模操作,那么您当前的方法会使RDD无意义。如果你不是,那么你可以像你建议的那样进行Scala集合操作,但那么为什么要费心去处理Spark的开销呢?

我会在DataFrame抽象级别运行,并将String列转换为Double,如下所示:

import sparkSession.implicits._

dataFrame
   .select("key", "value")
   .withColumn("key", 'key.cast(DoubleType))

这当然是假设在初始数据摄取时将key设置为Double后Spark已将inferSchema识别为true