在scala中展平任何列表

Mah*_*hah 0 scala

我有

val a = List(1, List(2,3), 4)
Run Code Online (Sandbox Code Playgroud)

我想将任何列表转换为List[Int].我怎样才能做到这一点?

预期的答案是:

List(1,2,3,4)
Run Code Online (Sandbox Code Playgroud)

lam*_*sta 5

你不能使用:

a.flatMap({
  case i: Int => List(i)
  case l: List[Int] => l
})
Run Code Online (Sandbox Code Playgroud)

case l: List[Int]由于类型擦除,该部分不起作用.事实上:

scala> val a = List(1, List("a"), 3)
a: List[Any] = List(1, List(a), 3)

scala> a.flatMap {
     |   case i: Int => List(i)
     |   case l: List[Int] => l
     | }
<console>:11: warning: non-variable type argument Int in type pattern List[Int] (the underlying of List[Int]) is unchecked since it is eliminated by erasure
          case l: List[Int] => l
                  ^
res2: List[Int] = List(1, a, 3)

scala> res2(1) // boom!
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer 
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:105)
  ... 33 elided
Run Code Online (Sandbox Code Playgroud)

在这些情况下,您可能需要考虑使用无形Typeable类型类进行类型安全转换.例如:

scala> import shapeless.syntax.typeable._
import shapeless.syntax.typeable._

scala> val as = a.flatMap {
     |   case x: Int => List(x)
     |   case xs => xs.cast[List[Int]].getOrElse(List())
     | }
as: List[Int] = List(1, 2, 3, 4)

scala> val b = List(1, 2, List("a", "b"), 3)
b: List[Any] = List(1, 2, List(a, b), 3)

scala> val bs = b.flatMap {
     |   case x: Int => List(x)
     |   case xs => xs.cast[List[Int]].getOrElse(List())
     | }
bs: List[Int] = List(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)

正如您可以cast[T]通过无形通过方法添加到每个类型的方法一样,如果转换失败,则implicits返回Option[T]其值None,Some如果成功的话.

当然,如果你的第一个列表的内容不是a Int或a,你可以决定失败List[Int].在我的例子中,我决定忽略其他类型,仍然产生一个List[Int].