52

我有这样的班级结构

abstract class A
class B extends A
class C extends A
class D extends A
class E extends A

我收集了各种实例,例如:

val xs = List(new D, new B, new E, new E, new C, new B)

我的问题是,有没有一种优雅的方法可以从列表中过滤掉一些子类?

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

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

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

4

3 回答 3

105

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

获取类型 A 的所有值:

xs.collect { case a: A => a }

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

xs diff xs.collect { case x@(_: B | _: C) => x }
于 2015-07-10T18:39:42.077 回答
53

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

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

在您的情况下,您得到 aList[ScalaObject]因为是,和ScalaObject的最小上限。NoneDE

于 2012-11-14T15:44:21.330 回答
4

将问题表述为问题似乎是解决它们的一种很好的方法:) 我的问题实际上提供了答案 - 只需按子类型过滤:

val ys = xs filterNot(List(classOf[B], classOf[C]) contains _.getClass)
于 2012-11-14T15:41:14.947 回答