scala 返回列表中的第一个 Some
我有一个列表 l:List[T1]
,目前正在执行以下操作:
myfun : T1 -> Option[T2]
val x: Option[T2] = l.map{ myfun(l) }.flatten.find(_=>true)
myfun
函数返回 None 或 Some,flatten 丢弃所有 None,find 返回第一个列表的元素(如果有)。
这对我来说似乎有点老套。我认为可能存在一些理解或类似的东西,可以减少浪费或更聪明。 例如:如果 myfun
在列表 map
期间返回 any Some
,我不需要任何后续答案>l。
I have a list l:List[T1]
and currently im doing the following:
myfun : T1 -> Option[T2]
val x: Option[T2] = l.map{ myfun(l) }.flatten.find(_=>true)
The myfun
function returns None or Some, flatten throws away all the None's and find returns the first element of the list if any.
This seems a bit hacky to me. Im thinking that there might exist some for-comprehension or similar that will do this a bit less wasteful or more clever.
For example: I dont need any subsequent answers if myfun
returns any Some
during the map
of the list l
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
怎么样:
Stream 是惰性的,因此它不会提前映射所有内容,但也不会重新映射内容。不要将事物展平,而是将
Option
转换为List
,以便可以使用flatMap
。How about:
Stream is lazy, so it won't map everything in advance, but it won't remap things either. Instead of flattening things, convert
Option
toList
so thatflatMap
can be used.除了使用
toStream
来使搜索变得懒惰之外,我们还可以使用Stream::collectFirst
:此:
将
List
转换为Stream
,以便尽早停止搜索。使用
myFun
作为Option[T]
转换元素。收集第一个非
None
的映射元素并提取它。从 Scala 2.13 开始,随着
Stream
的弃用而转而使用LazyList
,这将变成:In addition to using
toStream
to make the search lazy, we can useStream::collectFirst
:This:
Transforms the
List
into aStream
in order to stop the search early.Transforms elements using
myFun
asOption[T]
s.Collects the first mapped element which is not
None
and extract it.Starting
Scala 2.13
, with the deprecation ofStream
s in favor ofLazyList
s, this would become:好吧,这几乎,但不完全,
但是您从 myfun 返回一个
Option
而不是List
,所以这可能不起作用。如果是这样(我手头没有 REPL),请尝试:Well, this is almost, but not quite
But you are returning a
Option
rather than aList
from myfun, so this may not work. If so (I've no REPL to hand) then try instead:嗯,for-communeration 的等价物非常简单
,如果你真的进行翻译,其结果与 oxbow_lakes 给出的结果相同。假设 List.flatmap 有合理的惰性,这既是一个干净又有效的解决方案。
Well, the for-comprehension equivalent is pretty easy
which, if you actually do the the translation works out the same as what oxbow_lakes gave. Assuming reasonable laziness of List.flatmap, this is both a clean and efficient solution.
截至2017年,之前的答案似乎已经过时了。我运行了一些基准测试(1000 万个整数的列表,第一个匹配项大致在中间,Scala 2.12.3、Java 1.8.0、1.8 GHz Intel Core i5)。除非另有说明,
list
和map
具有以下类型:只需在列表上调用
map
:~1000 ms第一次调用
toStream< /code> 在列表上:~1200 ms
在列表上调用
toStream.flatMap
:~450 ms在列表上调用
flatMap
:~100 ms第一次调用
iterator列表中的
:约 35 毫秒递归函数
find()
:约 25 毫秒迭代函数
find()
:约 25 毫秒您可以通过以下方式进一步加快速度:使用 Java 而不是 Scala 集合以及功能较少的风格。
循环遍历
java.util.ArrayList
中的索引:~15 ms循环遍历
java.util.ArrayList
中的索引,函数返回null
而不是 < code>None:~10 ms(当然,通常会将参数类型声明为
java.util.List
,而不是java.util.ArrayList
。我在这里选择了后者,因为它是我用于基准测试的类。java.util.List
的其他实现将显示不同的性能 - 大多数都会更差。)As of 2017, the previous answers seem to be outdated. I ran some benchmarks (list of 10 million Ints, first match roughly in the middle, Scala 2.12.3, Java 1.8.0, 1.8 GHz Intel Core i5). Unless otherwise noted,
list
andmap
have the following types:Simply call
map
on the list: ~1000 msFirst call
toStream
on the list: ~1200 msCall
toStream.flatMap
on the list: ~450 msCall
flatMap
on the list: ~100 msFirst call
iterator
on the list: ~35 msRecursive function
find()
: ~25 msIterative function
find()
: ~25 msYou can further speed up things by using Java instead of Scala collections and a less functional style.
Loop over indices in
java.util.ArrayList
: ~15 msLoop over indices in
java.util.ArrayList
with function returningnull
instead ofNone
: ~10 ms(Of course, one would usually declare the parameter type as
java.util.List
, notjava.util.ArrayList
. I chose the latter here because it's the class I used for the benchmarks. Other implementations ofjava.util.List
will show different performance - most will be worse.)