鉴于异构序列,我如何只提取某种类型的成员,并以类型安全的方式对这些成员进行操作?
如果我有:
trait Foo
case class Bar(baz: String)
case class Qux(bar: Bar, quux: String) extends Foo
case class Corge(grault: Int) extends Foo
如果我想采用混合Corges
和Quxes
...
val s = Seq[Foo](Corge(1), Qux(Bar("2"), "3"), Qux(Bar("4"), "5"), Corge(6), Qux(Bar("2"), "7"))
...并提取Quxes
,按Bar
分组:
Map(
Bar(2) -> List(Qux(Bar(2),3), Qux(Bar(2),7)),
Bar(4) -> List(Qux(Bar(4),5))
)
我可以这样做:
s filter { f => f.isInstanceOf[Qux] } groupBy {
f => f.asInstanceOf[Qux].bar }
或者我可以这样做:
(s.filter({ f => f.isInstanceOf[Qux] }).asInstanceOf[Seq[Qux]]) groupBy {
q => q.bar }
但无论哪种方式,我需要进行两次instanceOf
次检查,当我看起来应该可以逃脱一次。或者没有。是否有一些我缺少的聪明的模式匹配解决方案?
答案 0 :(得分:12)
比丹尼尔·马丁的解决方案更好的是使用collect
:
val a: Seq[Any] = List(1, 2, "asdf", 4)
a: Seq[Any] = List(1, 2, asdf, 4)
val b = a collect { case s: String => s }
b: Seq[String] = List(asdf)
答案 1 :(得分:1)
不需要明确的instanceOf
,只是使用case
中的类所隐含的类型:
$ scala
Welcome to Scala version 2.9.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val a : Seq[Any] = List(1, 2, "asdf", 4)
a: Seq[Any] = List(1, 2, asdf, 4)
scala> val b = a flatMap {i:Any => i match { case s:String => Some(s); case _ => None }}
b: Seq[String] = List(asdf)
请注意a
和b
的类型。