【发布时间】:2020-06-16 22:10:47
【问题描述】:
我来自 Pyspark。我知道如何在 Pyspark 中做到这一点,但在 Scala 中却没有做到这一点。
这是一个数据框,
val df = Seq(
("u1", Array[Int](2,3,4)),
("u2", Array[Int](7,8,9))
).toDF("id", "mylist")
// +---+---------+
// | id| mylist|
// +---+---------+
// | u1|[2, 3, 4]|
// | u2|[7, 8, 9]|
// +---+---------+
这是一个 Map 对象,
val myMap = (1 to 4).toList.map(x => (x,0)).toMap
//myMap: scala.collection.immutable.Map[Int,Int] = Map(1 -> 0, 2 -> 0, 3 -> 0, 4 -> 0)
所以这个映射的键值是从 1 到 4。
对于 df 的每一行,我想检查“mylist”中的任何元素是否包含在 myMap 中作为键值。如果 myMap 包含一个元素,则返回该元素(如果包含多个元素,则返回任意一个),否则返回 -1。
所以结果应该是这样的
+---+---------+-------+
| id| mylist| label|
+---+---------+-------+
| u1|[2, 3, 4]| 2 |
| u2|[7, 8, 9]| -1 |
+---+---------+-------+
我尝试了以下方法:
- 以下函数适用于数组对象,但不适用于列:
def list2label(ls: Array[Int],
m: Map[Int, Int]):(Int) = {
var flag = 0
for (element <- ls) {
if (m.contains(element)) flag = element
}
flag
}
val testls = Array[Int](2,3,4)
list2label(testls, myMap)
//testls: Array[Int] = Array(2, 3, 4)
//res33: Int = 4
- 尝试使用 UDF,但出现错误:
def list2label_udf(m: Map[Int, Int]) = udf( (ls: Array[Int]) =>(
var flag = 0
for (element <- ls) {
if (m.contains(element)) flag = element
}
flag
)
)
//<console>:3: error: illegal start of simple expression
// var flag = 0
// ^
我认为我的 udf 格式错误..
- 在 Pyspark 中,我可以随心所欲地做到这一点:
%pyspark
myDict={1:0, 2:0, 3:0, 4:0}
def list2label(ls, myDict):
for i in ls:
if i in dict3:
return i
return 0
def list2label_UDF(myDict):
return udf(lambda c: list2label(c,myDict))
df = df.withColumn("label",list2label_UDF(myDict)(col("mylist")))
任何帮助将不胜感激!
【问题讨论】:
-
@user10938362 谢谢,我相信这提出了一个更普遍的问题,但是与这种情况相比,我的额外问题是需要在 UDF 中编写多行方法。所以我提出这个问题。显然,从接受的答案来看,我错误地使用了括号。
标签: scala apache-spark user-defined-functions