Допустим, я хочу, чтобы сгладить вложенные списки одного и того же типа ... НапримерСведение вложенные списки одного и того же типа
ListA(Element(A), Element(B), ListA(Element(C), Element(D)), ListB(Element(E),Element(F)))
ListA
содержит вложенный список того же типа (ListA(Element(C), Element(D))
), поэтому я хочу, чтобы заменить она со значениями, которые он содержит, поэтому результат верхнего примера должен выглядеть следующим образом:
ListA(Element(A), Element(B), Element(C), Element(D), ListB(Element(E),Element(F)))
иерархия Текущий класс:
abstract class SpecialList() extends Exp {
val elements: List[Exp]
}
case class Element(name: String) extends Exp
case class ListA(elements: List[Exp]) extends SpecialList {
override def toString(): String = "ListA("+elements.mkString(",")+")"
}
case class ListB(elements: List[Exp]) extends SpecialList {
override def toString(): String = "ListB("+elements.mkString(",")+")"
}
object ListA{def apply(elements: Exp*):ListA = ListA(elements.toList)}
object ListB{def apply(elements: Exp*):ListB = ListB(elements.toList)}
Я сделал три решения, работает, но я думаю, что должен быть лучший способ для достижения этой цели:
Первое решение:
def flatten[T <: SpecialList](parentList: T): List[Exp] = {
val buf = new ListBuffer[Exp]
for (feature <- parentList.elements) feature match {
case listA:ListA if parentList.isInstanceOf[ListA] => buf ++= listA.elements
case listB:ListB if parentList.isInstanceOf[ListB] => buf ++= listB.elements
case _ => buf += feature
}
buf.toList
}
Второе решение:
def flatten[T <: SpecialList](parentList: T): List[Exp] = {
val buf = new ListBuffer[Exp]
parentList match {
case listA:ListA => for (elem <- listA.elements) elem match {
case listOfTypeA:ListA => buf ++= listOfTypeA.elements
case _ => buf += elem
}
case listB:ListB => for (elem <- listB.elements) elem match {
case listOfTypeB:ListB => buf ++= listOfTypeB.elements
case _ => buf += elem
}
}
buf.toList
}
Третье решение
def flatten[T <: SpecialList](parentList: T): List[Exp] = parentList.elements flatMap {
case listA:ListA if parentList.isInstanceOf[ListA] => listA.elements
case listB:ListB if parentList.isInstanceOf[ListB] => listB.elements
case other => List(other)
}
Мой вопрос в том, есть ли какой-либо лучший, более общий способ достижения такой же функциональности, как и во всех трех верхних решениях, происходит повторение кода?
Это дерево, нет? – ziggystar
В некотором роде это .. Если есть что-то еще, что я должен объяснить, пожалуйста, дайте мне знать ... Третье решение ближе всего, я могу получить, но мне не нравятся два почти одинаковых оператора case (для ListA и ListB) ... Должен быть более общий способ сделать это, возможно, с параметрами типа? – PrimosK
Ответ зависит от того, что вы имеете в виду * лучше *. Третье решение - это краткое функциональное решение. Используя 'scalaz', вы можете представить свои данные как' Tree', а затем просто называть '.flatten'. Вы уверены, что ваше дерево имеет только глубину 2? – ziggystar