#scala #apache-spark #recursion #linked-list #self-reference
#scala #apache-spark #рекурсия #связанный список #самоссылка
Вопрос:
Моя исходная структура данных содержит самоссылки, которые не поддерживаются spark:
initial.toDF
java.lang.UnsupportedOperationException: cannot have circular references in class, but got the circular reference
Исходная структура данных:
case class FooInitial(bar:String, otherSelf:Option[FooInitial])
val initial = Seq(FooInitial("first", Some(FooInitial("i1", Some(FooInitial("i2", Some(FooInitial("finish", None))))))))
Чтобы исправить это, семантически похожее и желаемое представление может быть:
case class Inner(value:String)
case class Foo(bar:String, otherSelf:Option[Seq[Inner]])
val first = Foo("first", None)
val intermediate1 = Inner("i1")//Foo("i1", None)
val intermediate2 = Inner("i2")//Foo("i2", None)
val finish = Foo("finish", Some(Seq(intermediate1, intermediate2)))
val basic = Seq(first, finish)
basic.foreach(println)
val df = basic.toDF
df.printSchema
df.show
------ ------------
| bar| otherSelf|
------ ------------
| first| null|
|finish|[[i1], [i2]]|
------ ------------
Каков хороший функциональный способ преобразования из начального в другое, не связанное с самим собой
представление?
Ответ №1:
Это рекурсивно разыменовывает объекты:
class MyCollector {
val intermediateElems = new ListBuffer[Foo]
def addElement(initialElement : FooInitial) : MyCollector = {
intermediateElems = Foo(initialElement.bar, None)
intermediateElems addIntermediateElement(initialElement.otherSelf, ListBuffer.empty[Foo])
this
}
@tailrec private def addIntermediateElement(intermediate:Option[FooInitial], l:ListBuffer[Foo]) : ListBuffer[Foo] = {
intermediate match {
case None => l
case Some(s) => {
intermediatePoints = Foo(s.bar "_inner", None)
addIntermediateElement(s.otherSelf,intermediatePoints)
}
}
}
}
initial.foldLeft(new MyCollector)((myColl,stay)=>myColl.addElement(stay)).intermediatePoints.toArray.foreach(println)
Результатом является список:
Foo(first,None)
Foo(i1_inner,None)
Foo(i2_inner,None)
Foo(finish_inner,None)
что теперь прекрасно работает для spark.
ПРИМЕЧАНИЕ: это не 1: 1 для того, что я просил изначально, но для меня пока достаточно.