読者です 読者をやめる 読者になる 読者になる

by shigemk2

当面は技術的なことしか書かない

collectFirst

Scala

caseにマッチした最初の値を返す、というもの。

scala> List(1,2,3).collectFirst{ case 2 => "two" }
res1: Option[String] = Some(two)

scala> List(1,2,3).collectFirst{ case 4 => "four" }
res2: Option[String] = None

Scalaコレクションメソッドメモ(Hishidama's Scala collection method Memo)

実装を見たら、こんな感じ。PartialFunctionを使っているようで。前半でリストをごにょごにょし、後半でBの関数でごにょごにょしているっぽい。ごにょごにょってなんだよ、馬鹿野郎。

scala/TraversableOnce.scala at 2.11.x · scala/scala · GitHub

  def collectFirst[B](pf: PartialFunction[A, B]): Option[B] = {
    // TODO 2.12 -- move out alternate implementations into child classes
    val i: Iterator[A] = self match {
      case it: Iterator[A] => it
      case _: GenIterable[_] => self.toIterator   // If it might be parallel, be sure to .seq or use iterator!
      case _ =>                                   // Not parallel, not iterable--just traverse
        self.foreach(pf.runWith(b => return Some(b)))
        return None
    }
    // Presumably the fastest way to get in and out of a partial function is for a sentinel function to return itself
    // (Tested to be lower-overhead than runWith.  Would be better yet to not need to (formally) allocate it--change in 2.12.)
    val sentinel: Function1[A, Any] = new scala.runtime.AbstractFunction1[A, Any]{ def apply(a: A) = this }
    while (i.hasNext) {
      val x = pf.applyOrElse(i.next, sentinel)
      if (x.asInstanceOf[AnyRef] ne sentinel) return Some(x.asInstanceOf[B])
    }
    None
  }