按类型过滤Scala列表

hez*_*amu 38 scala

我有这样的类结构

abstract class A
class B extends A
class C extends A
class D extends A
class E extends A
Run Code Online (Sandbox Code Playgroud)

我有各种实例的集合,例如:

val xs = List(new D, new B, new E, new E, new C, new B)
Run Code Online (Sandbox Code Playgroud)

我的问题是,是否有一种优雅的方法来过滤掉List中的一些子类?

假设我想要除B和C之外的所有实例.我可以用一堆isInstanceOf来做,或者像这样使用collect:

val ys = (xs collect {
    case b: B => None
    case c: C => None
    case notBorC => notBorC
}).filter(_ != None).asInstanceOf[List[A]]
Run Code Online (Sandbox Code Playgroud)

这有效,但感觉很尴尬,主要是因为滤镜和演员.有更优雅的方式吗?首选的代码较少,如果我添加更多的A子类,我希望有一个不需要更新的解决方案.

Gro*_*ozz 73

collect 可用于过滤定义函数的值:

获取类型A的所有值:

xs.collect { case a: A => a }
Run Code Online (Sandbox Code Playgroud)

获取除B和C之外的所有值:

xs diff xs.collect { case x@(_: B | _: C) => x }
Run Code Online (Sandbox Code Playgroud)


Tra*_*own 42

flatMap那狗屎!(正如他们所说):

scala> val ys = xs flatMap {
     |   case _: B | _: C => None
     |   case other => Some(other)
     | }
ys: List[A] = List(D@7ecdc97b, E@2ce07e6b, E@468bb9d1)
Run Code Online (Sandbox Code Playgroud)

在你的情况你得到一个List[ScalaObject],因为ScalaObject是最上限的None,DE.

  • 对于那些(比如我自己),想知道这是如何工作的:发生了隐式转换“option2iterable”,将“Some”/“None”值转换为可迭代。另一种不引发隐式转换的写法是使用“collect”,然后使用“flatten”而不是“flatMap”。很好的答案,特拉维斯! (2认同)