简体   繁体   English

在Scala中展平嵌套对象

[英]Flatten nested objects in Scala

Given a complex object like the following: 给定如下的复杂对象:

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

In action this can turn into something like this: 在行动中,这可以变成这样的事情:

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

I need to turn it into a flat list of Complex objects, pulling all the children/grandchildren up. 我需要把它变成一个Complex对象的平面列表,拉动所有的孩子/孙子。

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

Do you have any leads/ideas on how I can accomplish this? 你对我如何做到这一点有什么线索/想法吗?

The other solutions I have tried seem to only do simple nesting of lists. 我尝试过的其他解决方案似乎只是简单地嵌套列表。 Things I've tried: 我试过的事情:

These all seem to yield the same list I started with. 这些都似乎产生了我开始时的相同列表。

The difficulty in flattening of the input Seq here is that it is necessary to remove the nested references in the resulting list. 这里输入Seq扁平化的困难在于必须删除结果列表中的嵌套引用。 This can be done by copying the original object with nested = empty list and flattening all the sequences: 这可以通过使用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())
  )
def flattenComplex(c: Complex): Seq[Complex] = {
  if (c.nested.isEmpty) Seq(c)
  else Seq(c.copy(nested = Nil)) ++ c.nested.flatMap(flattenComplex _)
}

which gives: 这使:

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

Using 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())

My solution is mostly like those already posted, but avoids the (not so significant) inefficiency of putting the head element in a singleton collection when flattening a single element: 我的解决方案大多与已经发布的解决方案类似,但避免了在展平单个元素时将head元素放入singleton集合中的(不那么重要)效率低下:

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

as opposed to 而不是

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

to then be used as follows: 然后使用如下:

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

Notice that I also deferred substituting the nested elements with an empty list ( Nil ), decoupling with respect to the actual flattening, while still avoiding unneeded double passes leveraging view (more on that here ). 请注意,我还推迟使用空列表( Nil )替换nested元素,相对于实际展平进行解耦,同时仍然避免不需要的双通道利用view此处更多内容)。

You can play around with this solution on Scastie . 您可以在Scastie上使用此解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM