使用 x.head、x.tail 的原因:_* 在 Spark 中

Reason behind using x.head, x.tail: _* in Spark

我想更改数据框中列的顺序,发现正确的方法如下: val reorderedColumnNames: Array[String] = ??? // the new order of columns

val result: DataFrame = dataFrame.select(reorderedColumnNames.head, reorderedColumnNames.tail: _*)

我的问题是: 如果冒号“:_*”应该为您提供集合(Seq、List 或 Array)的所有元素,为什么不能像下面这样完成? val result: DataFrame = dataFrame.select(reorderedColumnNames: _*)

我不明白为什么第二种方式不被 Spark 接受(并产生错误),因为这两种方式应该是等价的

Dataset的API需要这样。

首先,Dataframe(我记得从 2.0 开始,或多或少)只是实现方面的 Dataset[Row],因此您必须检查 API doc of Dataset

查看 select 方法,有两种实现可供选择。

def select(col: String, cols: String*): DataFrame 

这个接受单个 String,后跟任意数量的 String

def select(cols: Column*): DataFrame 

这个接受任意数量的 Column 个实例。

您的示例代码:val reorderedColumnNames: Array[String] 是一个字符串数组。因此,您只能使用该方法的字符串变体,这需要使用至少一个 String 参数,后面可能还有其他参数。 这就是为什么你不能直接扩展你的数组。

如果您要将 Array[String] 转换为 Array[Column],它会起作用,即:

val reorderedColumnNamesAsCols: Array[Column] = reorderedColumnNames.map(col(_))
dataFrame.select(reorderedColumnNamesAsCols: _*)

现在为什么不也提出一个 select(cols: String*) 变体呢?我不知道是否/为什么有人提出这个建议,但我 猜测 它不会被编译器很好地播放。 我们可以检查:

scala> class Test {
 |   def test(strs: String*): Unit = {}
 |   def test(nbrs: Integer*): Unit = {}
 | }
<console>:13: error: double definition:
def test(strs: String*): Unit at line 12 and
def test(nbrs: Integer*): Unit at line 13
have same type after erasure: (strs: Seq)Unit
     def test(nbrs: Integer*): Unit = {}
         ^

编译器不高兴。