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
流是懒惰的,因此不会提前绘制所有内容,但也不会重新映射内容。而不是变平的,而是转换 Option
到 List
以便 flatMap
可以使用。
其他提示
好吧,这是 几乎,但不完全
val x = (l flatMap myfun).headOption
但是你正在返回 Option
而不是一个 List
从myfun那里,所以这可能行不通。如果是这样(我没有重复),然后尝试:
val x = (l flatMap(myfun(_).toList)).headOption
除了使用 toStream
为了使搜索懒惰,我们可以使用 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
支持 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所提供的相同。假设列表合理的懒惰。flatmap,这既是干净有效的解决方案。
截至2017年,先前的答案似乎已经过时了。我进行了一些基准测试(1000万个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 ms
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 ms
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
}
您可以通过使用Java代替Scala集合和功能较低的样式来进一步加快事物的速度。
在索引中循环 java.util.ArrayList
: :〜15 ms
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 ms
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
将显示出不同的性能 - 大多数会更糟。)