在Scala中展平嵌套对象

时间:2018-05-18 13:33:18

标签: scala flatten flatmap

给出如下的复杂对象:

case class Complex
(
  id: Long,
  name: String,
  nested: Seq[Complex]
)

在行动中,这可能变成这样的事情:

val stuff =
  List(
    Complex(1, "name1",
      List(
        Complex(2, "name2", List()),
        Complex(3, "name3",
          List(
            Complex(4, "name4", List())
          )
        )
      )
    )
  )

我需要将它变成Complex对象的平面列表,将所有的孩子/孙子孙女拉起来。

val flattened =
  List(
    Complex(1, "name1", List()),
    Complex(2, "name2", List()),
    Complex(3, "name3", List()),
    Complex(4, "name4", List()),
  )

您对如何实现这一目标有任何线索/想法吗?

我尝试的其他解决方案似乎只是简单地嵌套列表。 我尝试过的事情:

这些似乎都产生了我开始时的相同列表。

4 个答案:

答案 0 :(得分:2)

这里输入Seq扁平化的困难在于必须删除结果列表中的嵌套引用。这可以通过使用nested =空列表复制原始对象并展平所有序列来完成:

def flatten(obj: Complex): Seq[Complex] = {
  val unnested = obj.copy(nested = List())
  Seq(unnested) ++ obj.nested.flatMap(flatten)
}

println(stuff.flatMap(flatten))

List(
  Complex(1,name1,List()),
  Complex(2,name2,List()),
  Complex(3,name3,List()),
  Complex(4,name4,List())
  )

答案 1 :(得分:2)

def flattenComplex(c: Complex): Seq[Complex] = {
  if (c.nested.isEmpty) Seq(c)
  else Seq(c.copy(nested = Nil)) ++ c.nested.flatMap(flattenComplex _)
}

给出:

scala> stuff.flatMap(flattenComplex _)
res0: List[Complex] = List(Complex(1,name1,List()), Complex(2,name2,List()), Complex(3,name3,List()), Complex(4,name4,List()))

答案 2 :(得分:2)

使用Tail Recursion。

def flatten(source: Seq[Complex], dest: List[Complex]): List[Complex] = source match {
  case Nil => dest
  case x :: xs => flatten(xs, flatten(x.nested, dest :+ x.copy(nested = Nil)))
}
flatten(stuff, List())

答案 3 :(得分:2)

我的解决方案大多与已发布的解决方案类似,但避免了在展平单个元素时将head元素放入单例集合中的效率低下(不那么显着):

def flatten(complex: Complex): Seq[Complex] =
  complex +: complex.nested.flatMap(flatten)

而不是

def flatten(complex: Complex): Seq[Complex] =
  Seq(complex) ++ complex.nested.flatMap(flatten)

然后按如下方式使用:

stuff.view.flatMap(flatten).map(_.copy(nested = Nil))

请注意,我还推迟使用空列表(nested)替换Nil元素,与实际展平相关的解耦,同时仍然避免使用view的不必要的双遍(更多)在here)上。

您可以使用此解决方案on Scastie