Scalaは最初のリストに戻ります
-
30-09-2019 - |
質問
リストがあります 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なので、事前にすべてをマッピングすることはありませんが、物事も再表示することはありません。物事を平らにする代わりに、変換します Option
に List
となることによって 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
これ:
変換します
List
にStream
早期に検索を停止するため。使用して要素を変換します
myFun
なのでOption[T]
s。そうでない最初のマップ要素を収集します
None
そしてそれを抽出します。
起動 Scala 2.13
, 、の非推奨で Stream
sに賛成 LazyList
S、これは次のようになります。
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)。特に明記しない限り、 list
と map
次のタイプがあります。
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
異なるパフォーマンスを示します - ほとんどが悪化します。)