質問

リストがあります l:List[T1] そして現在、次のことをしています:

myfun : T1 -> Option[T2]
val x: Option[T2] = l.map{ myfun(l) }.flatten.find(_=>true)

myfun 関数はなしまたは一部を返し、フラットンはすべてのものをすべて捨て、リストの最初の要素を返します。

これは私には少しハッキーなようです。私は、これを少し無駄にしたり賢くしたりすることを行うために、理解のために存在するかもしれないと思っています。例:後続の回答は必要ありません myfun 戻り値 どれか Some 間に map リストの l.

役に立ちましたか?

解決

どうですか:

l.toStream flatMap (myfun andThen (_.toList)) headOption

ストリームは怠zyなので、事前にすべてをマッピングすることはありませんが、物事も再表示することはありません。物事を平らにする代わりに、変換します OptionList となることによって flatMap に使える。

他のヒント

まあ、これはそうです ほとんどですが、完全ではありません

val x = (l flatMap myfun).headOption

しかし、あなたはaを返しています Option ではなく List MyFunから、これはうまくいかないかもしれません。もしそうなら(私は手にするのはリプルではありません)、代わりに試してみてください:

val x = (l flatMap(myfun(_).toList)).headOption

使用に加えて toStream 検索を怠zyにするには、使用できます Stream::collectFirst:

List(1, 2, 3, 4, 5, 6, 7, 8).toStream.map(myfun).collectFirst { case Some(d) => d }
// Option[String] = Some(hello)
// given def function(i: Int): Option[String] = if (i == 5) Some("hello") else None

これ:

  • 変換します ListStream 早期に検索を停止するため。

  • 使用して要素を変換します myFun なので Option[T]s。

  • そうでない最初のマップ要素を収集します None そしてそれを抽出します。

起動 Scala 2.13, 、の非推奨で Streamsに賛成 LazyListS、これは次のようになります。

List(1, 2, 3, 4, 5, 6, 7, 8).to(LazyList).map(function).collectFirst { case Some(d) => d }

まあ、妥当な妥当なものは非常に簡単です

(for(x<-l, y<-myfun(x)) yield y).headOption

これは、実際に翻訳を行うと、oxbow_lakesが与えたものと同じように機能します。 list.flatmapの合理的な怠inessを想定すると、これはクリーンで効率的なソリューションの両方です。

2017年の時点で、以前の回答は時代遅れのようです。私はいくつかのベンチマークを実行しました(1,000万INTのリスト、最初の一致、ほぼ真ん中、Scala 2.12.3、Java 1.8.0、1.8 GHz Intel Core i5)。特に明記しない限り、 listmap 次のタイプがあります。

list: scala.collection.immutable.List
map: A => Option[B]

電話するだけです map リストの上:〜1000ミリ秒

list.map(map).find(_.isDefined).flatten

最初の呼び出し toStream リストの上:〜1200ミリ秒

list.toStream.map(map).find(_.isDefined).flatten

電話 toStream.flatMap リストの上:〜450ミリ秒

list.toStream.flatMap(map(_).toList).headOption

電話 flatMap リストの上:〜100ミリ秒

list.flatMap(map(_).toList).headOption

最初の呼び出し iterator リストの上:〜35ミリ秒

list.iterator.map(map).find(_.isDefined).flatten

再帰関数 find(): :〜25ミリ秒

def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
  list match {
    case Nil => None
    case head::tail => map(head) match {
      case None => find(tail, map)
      case result @ Some(_) => result
    }
  }
}

反復関数 find(): :〜25ミリ秒

def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
  for (elem <- list) {
    val result = map(elem)
    if (result.isDefined) return result
  }
  return None
}

Scalaコレクションと機能性の低いスタイルの代わりにJavaを使用して、物事をさらに高速化できます。

インデックスの上にループします java.util.ArrayList: :〜15ミリ秒

def find[A,B](list: java.util.ArrayList[A], map: A => Option[B]) : Option[B] = {
  var i = 0
  while (i < list.size()) {
    val result = map(list.get(i))
    if (result.isDefined) return result
    i += 1
  }
  return None
}

インデックスの上にループします java.util.ArrayList 関数が戻ってきます null それ以外の None: :〜10ミリ秒

def find[A,B](list: java.util.ArrayList[A], map: A => B) : Option[B] = {
  var i = 0
  while (i < list.size()) {
    val result = map(list.get(i))
    if (result != null) return Some(result)
    i += 1
  }
  return None
}

(もちろん、通常、パラメータータイプを次のように宣言します java.util.List, 、 いいえ java.util.ArrayList. 。私はここで後者を選びました。なぜなら、それは私がベンチマークに使用したクラスだからです。のその他の実装 java.util.List 異なるパフォーマンスを示します - ほとんどが悪化します。)

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top