【问题标题】:Flatten list of any in scala展平任何在scala中的列表
【发布时间】:2015-09-23 09:05:42
【问题描述】:

我有

val a = List(1, List(2,3), 4)

我想将该列表转换为List[Int]。我该怎么做?

预期答案是:

List(1,2,3,4)

【问题讨论】:

  • How to flatten List[Any]?的可能重复
  • 我不这么认为,因为 Mahek 想从 List[Any] 获得 List[Int]。相反,该问题询问如何从List[Any] 获取List[Any]
  • List[Any] 转换为任何类型,例如List[Int] 是一种代码味道。你想做什么?如果您在此List[Any] 中没有Int,您期望什么行为?
  • @KevinMeredith 我只检查一个条件IF 而我没有使用ELSE 这就是为什么我得到'List[Any]`
  • 我不明白,马赫克。想发布另一个 SO 问题吗?

标签: scala


【解决方案1】:

你不能使用:

a.flatMap({
  case i: Int => List(i)
  case l: List[Int] => l
})

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

在这些情况下,您可能需要考虑使用通过shapeless 获得的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)

cast[T] 方法可以通过 implicits 添加到每个类型,如果转换失败,则返回 Option[T],其值为 None,如果成功则返回 Some

当然,如果您的第一个列表的内容不是IntList[Int],您当然可以决定失败。在我的示例中,我决定忽略其他类型并仍然生成 List[Int]

【讨论】:

    【解决方案2】:

    我很确定您在整个代码中做错了什么。这不是您应该使用类型系统的方式。无论如何:

    val a = List(1, List(2,3), 4)
    
    a.flatMap({
      case i: Int => List(i)
      case l: List[Int] => l
    })
    

    【讨论】:

    • 谢谢..我是这门语言的初学者,所以我对类型系统不太擅长。我正在努力学习它。无论如何,非常感谢:)
    • @MahekShah 为什么你有List[Any]?总是尽量避免Any
    • 有时我在 map 语句中只使用一个条件,这就是为什么我得到任何列表的原因。但现在才知道首先过滤该条件,然后应用 map 函数,这样我可以避免@ 987654324@类型
    • 而且,如果我只想检查 IF 条件,例如 if(list.filter(condition).length>0) 则在没有 else 部分的情况下执行某些操作,那时我正在获取列表的Any。有什么办法可以防止这种情况发生?
    • @Reactormonk case l: List[Int] =&gt; l 由于类型擦除而无法工作。