如何在Scala中从for循环中获取单个元素?

12 浏览
0 Comments

如何在Scala中从for循环中获取单个元素?

就像这个问题:

循环并且提前退出的函数式代码

假设代码是

def findFirst[T](objects: List[T]):T = {
  for (obj <- objects) {
    if (expensiveFunc(obj) != null) return /*???*/ Some(obj)
  }
  None
}

如何在Scala中像这样从for循环中产生单个元素?

我不想使用原本问题中提出的find,我想知道如何使用for循环来实现。

* 更新 *

首先,感谢所有的评论,但我想我在问题中并不清楚。我希望得到像这样的东西:

val seven = for {
    x <- 1 to 10
    if x == 7
} return x

但它无法编译。出现两个错误:

-方法定义外返回

-方法main有返回语句,需要结果类型

我知道在这种情况下使用find()更好,我只是在学习和探索语言。在使用多个迭代器的更复杂情况下,我认为使用for查找实际上可以很有用。

感谢评论者,我将开始发放赏金来弥补糟糕的提问方式:)

admin 更改状态以发布 2023年5月22日
0
0 Comments

您可以将列表转换为流,以便for循环包含的任何过滤器仅在需求时进行评估。但从流中生成将始终返回流,而您想要的是可能性,因此,作为最后一步,您可以检查生成的流至少具有一个元素,并返回其头部作为即时。headOption函数正是这样做的。

def findFirst[T](objects: List[T], expensiveFunc: T => Boolean): Option[T] =
    (for (obj <- objects.toStream if expensiveFunc(obj)) yield obj).headOption

0
0 Comments

如果你想使用使用循环语句的for循环,它比.find.filter等链式调用的语法更简洁,有一个不错的技巧。而不是迭代严格的集合如列表,迭代惰性集合如迭代器或流。如果你开始是用一个严格的集合,用例如.toIterator使它变得惰性。

让我们看一个例子。

首先定义一个“吵闹”的整数,它将显示它何时被调用。

def noisyInt(i : Int) = () => { println("Getting %d!".format(i)); i }

现在让我们用一些这些填充列表:

val l = List(1, 2, 3, 4).map(noisyInt)

我们想查找第一个偶数的元素。

val r1 = for(e <- l; val v = e() ; if v % 2 == 0) yield v

上面的行导致:

Getting 1!
Getting 2!
Getting 3!
Getting 4!
r1: List[Int] = List(2, 4)

...意味着所有的元素都被访问了。考虑到结果列表包含所有偶数,这是有意义的。这次让我们迭代一个迭代器:

val r2 = (for(e <- l.toIterator; val v = e() ; if v % 2 == 0) yield v)

这样的结果是:

Getting 1!
Getting 2!
r2: Iterator[Int] = non-empty iterator

请注意,循环只执行到可以确定结果是空迭代器还是非空迭代器的那一点。

现在,要获取第一个结果,你只需要简单地调用r2.next

如果你想得到Option类型的结果,使用如下:

if(r2.hasNext) Some(r2.next) else None


Edit 这个编码的第二个例子只是:

val seven = (for {
    x <- (1 to 10).toIterator
    if x == 7
} yield x).next

,当然,如果你要使用.next,你应该确保始终至少有一个解决方案。或者,使用定义为所有TraversableheadOption,以获取Option[Int]

0