【问题标题】:Scala flatten list of String and List[String]Scala 展平 String 和 List[String] 的列表
【发布时间】:2017-03-13 08:19:40
【问题描述】:

在 Scala 扁平化方面需要一些帮助。

我有一个StringList[String] 的列表。

示例:List("I", "can't", List("do", "this"))

预期结果:List("I", "can't", "do", "this")

我做了很多实验,最紧凑的解决方案是:

val flattenList = list.flatten {
  case list: List[Any] => list
  case x => List(x)
}

但这似乎非常棘手且难以理解。对更幼稚的代码有什么建议吗?

谢谢。

【问题讨论】:

  • 你试过list.flatten。如果是这样,为什么它不适合你?
  • @maasg: flatten 不起作用,因为 list 包含不同的数据类型,包括 String 和 List[String]
  • 我认为@antonkw 想知道这是如何工作的。 flatten 假定列表包含另一个列表。所以,case list 按原样使用,case x 将 x 转换为列表。 flatten 文档中的示例会有所帮助:scala-lang.org/api/current/#scala.collection.immutable.List
  • @antonkw 为什么需要这个?这种方法的问题是List[Any] 可能是任何东西,所以你失去了类型安全。是否可以更改此列表的创建点,以便将 Strings 包装在列表中?像这样:List(List("I"), List("can't"), List("do", "this")) 而不是?

标签: scala collections functional-programming


【解决方案1】:

什么是“棘手和难以理解”是你在同一个列表中混合不同类型的元素。这就是你问题的根本原因。一旦你有了它,就没有办法不必扫描列表,并检查每个元素的类型来纠正它,你的解决方案和其他解决方案一样好(当然,比另一个更好)回答:))。

如果我是你的话,我真的会重新考虑导致拥有这样一个异构列表的代码路径。这并不是一个真正的好方法,因为您以这种方式颠覆了类型安全,并最终得到一个List[AnyRef],它可以包含......好吧,任何东西。

【讨论】:

  • 是的。你说得对。我是 scala 的新手,有时语言的特性会导致糟糕的解决方案只是因为它们有效:) 但在这种情况下,我应该开始重构。谢谢。
  • 正是我的想法。我很想 +1,但严格来说,这更像是评论而不是答案。
  • @maasg 这是一个答案,好吧。问题是这是否是比 OP 更好的扁平化方式。答案是不”。 :)
  • 经过深思熟虑 +1 :-)
【解决方案2】:

我认为您无法避免处理两种情况:单个元素与列表。您必须以一种或另一种方式告诉您的程序要做什么。这是一个更通用的实现,可以处理任意深度的列表:

def flattenList(xs: List[Any]): List[Any] =
  xs match {
    case Nil => Nil
    case (ys:List[_]) :: t => flattenList(ys) ::: flattenList(t)
    case h :: t => h :: flattenList(t)
  }

例子:

scala> flattenList(List("I", "can't", List("do", "this")))
res1: List[Any] = List(I, can't, do, this)

scala> flattenList(List("I", "can't", List("do", List("this", "and", "this"))))
res2: List[Any] = List(I, can't, do, this, and, this)

虽然这看起来不是很安全。尝试使用树或其他东西。

【讨论】: