【发布时间】:2020-08-22 10:47:34
【问题描述】:
假设我们有一个Any的序列
val seq = Seq(1,2,null)
seq: Seq[Any] = List(1, 2, null)
现在如果过滤非空元素获得一个新序列
val cleanSeq = seq.filterNot(_ == null)
cleanSeq: Seq[Any] = List(1, 2)
现在我想获得与创建类似cleanSeq 这样的新序列时获得的相同类型
val seq2 = Seq(1,2)
seq2: Seq[Int] = List(1, 2)
我可以从cleanSeq开始以某种方式获得Seq[Int]吗?
更新
前面只是一个虚拟示例,我可以有除Int 之外的其他类型,也可以有复杂类型示例:Array[Map[String, Float]]。
我能做的唯一假设是我有一个可能包含空值的序列。但是序列中的其他元素除了Any 之外都有一个共同的超类型。去掉空值后,我想找到常见的超类型。
更新
用例
我想从具有名称和值的列创建火花数据框。这些值存储在Seq 中。从Seq 的类型我想导出数据框的架构。
列的定义
import reflect.runtime.universe._
import org.apache.spark.sql.catalyst.ScalaReflection
import org.apache.spark.sql.types._
case class InternalColumn[A: TypeTag](colName: String, col: Seq[A]) {
private def getType: DataType = ScalaReflection.schemaFor[A].dataType
def genStructField: StructField = StructField(colName, getType)
}
创建数据框:
def createDF[T](data: Seq[T], sch: StructType): DataFrame = {
val dataRow: Seq[Row] = data.map {
case row: Row => row
case prod: Product => Row(prod.productIterator.toSeq: _*)
case d => Row(d)
}
spark.createDataFrame(sc.makeRDD(dataRow), sch)
}
用法
def createFromColumns(data: Seq[InternalColumn[_]]): DataFrame = {
def loop(schema: StructType, cols: Seq[InternalColumn[_]]): StructType = cols.toList match {
case Nil => schema
case h :: t => loop(schema.add(h.genStructField), t)
}
val sch: StructType = loop(new StructType(), data)
createDF(data.map(_.col).transpose.map(Row.fromSeq), sch)
}
val df = createFromColumns(List(InternalColumn("c1", List(1,2,3)), InternalColumn("c2", List("a", "b", "c"))))
scala> df.show()
+---+---+
| c1| c2|
+---+---+
| 1| a|
| 2| b|
| 3| c|
+---+---+
scala> df.printSchema
root
|-- c1: integer (nullable = true)
|-- c2: string (nullable = true)
到目前为止效果很好。但是有人可能想要创建一个数据框,其中包含一个包含空值的列。如果具有 null 的列可以为空,例如它具有 StringType,那么它仍然有效。
当您在不可为空的列中有空值时会出现问题,例如:
scala> val df = createFromColumns(List(InternalColumn("c1", List(1,2,null)), InternalColumn("c2", List("a", "b", "c"))))
java.lang.UnsupportedOperationException: Schema for type Any is not supported
这就是我想在删除所有空值时推断序列类型的原因。
【问题讨论】:
-
如果您在编译时无法知道类型应该是什么,那么编译器也无法知道。 Seq 在运行时 中的元素的通用超类型只能在在运行时 知道。所以编译器无能为力。
-
你可能在编译时对类型有很好的了解,考虑使用
Either -
所以如果我做对了,简短的回答是不,这是不可能的。谢谢!
-
视情况而定。你从哪里得到这个
List(1,2,null)?如果某处有一个黑盒向您抛出一个或多个Seq[Any],则无法在编译时恢复该类型。