【问题标题】:Flatten nested objects in Scala在 Scala 中展平嵌套对象
【发布时间】:2018-10-28 23:09:59
【问题描述】:

给定一个复杂的对象,如下所示:

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

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

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

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

【问题讨论】:

  • 在我测试我的解决方案的时间里,这个页面中出现的单词 flat 的次数已经增加到 32。:-)

标签: scala flatten flatmap


【解决方案1】:

我的解决方案大多类似于已经发布的解决方案,但避免了在展平单个元素时将 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))

请注意,我还推迟了用空列表 (Nil) 替换 nested 元素,与实际扁平化解耦,同时仍避免利用 view 进行不必要的双通道(更多关于 here) .

你可以试试这个解决方案on Scastie

【讨论】:

  • complex +: vs Seq(complex) ++List() vs Nil.view +1
【解决方案2】:

使用尾递归。

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

【讨论】:

  • 不错的解决方案,但不是真正的railrec,因为在尾部位置有一个嵌套的flatten 调用。
【解决方案3】:
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()))

【讨论】:

    【解决方案4】:

    这里对输入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())
      )
    

    【讨论】:

    • 这正是我想要的!谢谢! @Antot
    • 只是指出:这个解决方案是一个递归函数,这是一种理想的迭代函数方法。
    猜你喜欢
    • 2018-10-24
    • 2019-07-20
    • 2017-07-02
    • 2020-12-22
    • 1970-01-01
    • 2014-05-28
    • 2015-04-18
    • 2021-10-19
    • 2020-06-23
    相关资源
    最近更新 更多