【问题标题】:How to flatten List[Any]?如何展平 List[Any]?
【发布时间】:2014-12-28 19:13:06
【问题描述】:

在 Scala 中,如何将其展平:

List(1, List(2, 3), 4, List(5, 6, 7))

进入这个

List(1, 2, 3, 4, 5, 6, 7)

?

【问题讨论】:

  • 如果你能避免一开始就使用List[Any],你的生活会好很多。
  • 先把它转换成一个健全的数据类型,然后使用常规的flatten方法?

标签: scala


【解决方案1】:

来自scala99 problems的通用解决方案

def flatten(ls: List[Any]): List[Any] = ls flatMap {
case ms: List[_] => flatten(ms)
case e => List(e)
}                                               //> flatten: (ls: List[Any])List[Any]

flatten(List(1, List(2,3), 4, List(5,6,7)))     //> res0: List[Any] = List(1, 2, 3, 4, 5, 6, 7)

【讨论】:

    【解决方案2】:

    如果你必须处理Any,你可以在运行时通过模式匹配来做到这一点:

    def flatten(l: List[_]): List[Any] = l flatMap {
      case m: List[_] => flatten(m)
      case e => List(e)
    }
    

    但正如@Erik 所说,最好始终跟踪类型信息,这样您就可以确保正确处理所有情况。对于 Erik 解决方案的更通用版本,您可以使用 shapeless:https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/flatten.scala(该示例使用元组,但同样的事情与 HLists 的工作方式相同)

    【讨论】:

      【解决方案3】:

      您应该改用Either[Int, List[Int]] 的列表:

      val xs: List[Either[Int, List[Int]]] = List(Left(1), Left(2), Right(List(1, 2, 3)), Left(7))
      val xs1 = xs.flatMap {
        case Left(i)   => List(i)
        case Right(is) => is
      }
      

      另一方面,您可以通过不首先生成此类异构列表来解决问题。

      可选:

      使用 Scalaz 的 \/,将 Either[Int, List[Int]] 替换为 Int \/ List[Int]

      val xs: List[Int \/ List[Int]] = ...
      
      val xs1 = xs.map {
        case -\/(i)  => ...
        case \/-(is) => ...
      }
      

      【讨论】:

      • 反对票不需要 cmets。我的是,引入 Scalaz 需要更改输入列表的类型,我们遇到了两个问题:(
      • Scalaz 位是可选的!
      猜你喜欢
      • 1970-01-01
      • 2014-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多