如何在列中更改字符串值的顺序

时间:2017-06-21 14:05:14

标签: scala apache-spark apache-spark-sql

如何使用scala udf更改字符串的顺序

   root
    |-- Loc: string (nullable = true)
    +----------------+
    |             Loc|
    +----------------+
    |8106f510000dc502|
    +----------------+
8106f510000dc502 to 08f150000dc50261

我想按照这个顺序转换它[3,1,5,7,6,(8-16),4,2]

3 个答案:

答案 0 :(得分:2)

出现就像Scala编码一样,几乎与Spark无关。

我会做以下事情:

// the dataset
val loc = Seq("8106f510000dc502").toDF("Loc")

// the udf for decoding loc
def mydecode(codes: Seq[Int]) = udf { s: String =>
  codes.map(pos => s.charAt(pos)).mkString
}

val codes = Seq(3,1,5,7,6,4,2)
val decoded = loc.withColumn("decoded", mydecode(codes)($"loc"))
scala> decoded.show
+----------------+-------+
|             Loc|decoded|
+----------------+-------+
|8106f510000dc502|61501f0|
+----------------+-------+

我将离开codes阵列中的范围,即(8-16)作为您的主场练习。

答案 1 :(得分:0)

如果您希望在100z200列上从200z100转到Loc,那么定义udf功能如下所示就足够了(假设您有z }在列中每个字符串的中间)

def reverseReplace = udf((str: String) => {
  val index = str.indexOf("z")
  str.substring(index+1, str.length)+str.substring(index, index+1)+str.substring(0, index)
})

您可以将udf功能称为

val m4=msc3.select("Loc").withColumn("Info", reverseReplace($"Loc"))
m4.show(false)

您将获得以下输出

+-------+-------+
|Loc    |Info   |
+-------+-------+
|100z200|200z100|
|30z400 |400z30 |
|600z10 |10z600 |
+-------+-------+

<强>被修改

根据我从您的更新问题中了解到您希望以[3,1,5,7,6,(8-16),4,2]顺序获得最终结果的内容,以下内容可以是您的udf函数

def reverseReplace = udf((str: String) => {
  val len = str.length
  val index = 16 > len match {case true => len case false => 16}
  var finalStr = ""
  if(len > 2)
    finalStr += str.substring(3-1,3)
  if(len > 0)
    finalStr += str.substring(1-1,1)
  if(len > 4)
    finalStr += str.substring(5-1,5)
  if(len > 6)
    finalStr += str.substring(7-1,7)
  if(len > 5)
    finalStr += str.substring(6-1,6)
  if(len > 7)
    finalStr += str.substring(8-1, index)
  if(len > 3)
    finalStr += str.substring(4-1,4)
  if(len > 1)
    finalStr += str.substring(2-1,2)
  if(finalStr == "")
    finalStr = str
  finalStr
})

您可以按照上述说明调用此udf功能

答案 2 :(得分:0)

使用正则表达式和可分配分隔符的UDF的另一种方法(在本例中为&#34; z&#34;):

def flip(sep: String) = udf(
  (s: String) => {
    val pattern = s"""(.*?)${sep}(.*)""".r
    s match {
      case pattern(a, b) => b + sep + a
    }
  }
)

val df = Seq( ("100z200") ).toDF("Loc")

val dfFlipped = df.withColumn("Flipped", flip("z")($"Loc"))

dfFlipped.show
+-------+-------+
|    Loc|Flipped|
+-------+-------+
|100z200|200z100|
+-------+-------+