В Scala 2.13 вы можете использовать:
val person = Person("John", 23)
(person.productEleementNames zip person.productIterator).foldLeft(dataFrame) {
case (dataFrame, (name, value)) =>
dataFrame.withColumn(name, value) // example
}
, но, поскольку вы находитесь на 2.11 или, в лучшем случае, на 2.12 из-за Spark, вы должны использовать другой способ.
Одним из способов будет использование отражения во время выполнения:
(person.getClass.getDeclaredFields.map(_.getName) zip person.productIterator).foldLeft(dataFrame) {
case (dataFrame, (name, value)) =>
dataFrame.withColumn(name, value) // example
}
это будет иметь штраф за время выполнения, но не потребует каких-либо зависимостей.
Другим вариантом будет использование бесформенного или магнолийного для вычисления результата во время компиляции (при условии, что вы знаете тип того, из чего вы хотите извлечь имена полей).
Бесформенное решение уже предоставлено в другом вопросе .
Решение Magnolia было бы что-то вроде (отказ от ответственности: не проверяется, если он компилируется):
import magnolia._
trait FieldNames[T] {
def apply(): List[String]
}
object FieldNames {
def getNames[T](implicit fieldNames: FieldNames[T]): FieldNames[T] = fieldNames
type Typeclass[T] = FieldNames[T]
def combine[T](ctx: ReadOnlyCaseClass[Typeclass, T]): FieldNames[T] = () =>
ctx.parameters.map(_.label).toList
}
implicit def gen[T]: FieldNames[T] = macro Magnolia.gen[T]
}
(FieldNames.getNames[Person] zip person.productIterator).foldLeft(dataFrame) {
case (dataFrame, (name, value)) =>
dataFrame.withColumn(name, value) // example
}
Отражение времени компиляции требует немного больше усилий и предполагает, что вы знаете тип значения, с которым вы работаете во время компиляции, но должны Быстрее во время выполнения и меньше подверженных ошибкам.
Короче говоря, какой из них лучше, зависит от вашего варианта использования.