如何从scala中的for循环生成单个元素?

如何从scala中的for循环生成单个元素?,scala,Scala,很像这个问题: 说代码是 def findFirst[T](objects: List[T]):T = { for (obj <- objects) { if (expensiveFunc(obj) != null) return /*???*/ Some(obj) } None } def findFirst[T](对象:列表[T]):T={ 对于(obj,所以你要做的是在你的条件得到满足后打破一个循环。这里的答案可能就是你想要的 总的来说,为了理解Scala,需

很像这个问题:

说代码是

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

对于(obj,所以你要做的是在你的条件得到满足后打破一个循环。这里的答案可能就是你想要的


总的来说,为了理解Scala,需要将其转换为map、flatmap和filter操作。因此,除非您抛出异常,否则不可能中断这些函数。

为什么不完全按照上面的草图执行,即,
尽早从循环中返回
?如果您对Scala在引擎盖下的实际操作感兴趣,使用
-print
运行代码。Scala将循环分解为
foreach
,然后使用异常过早地离开
foreach

如果您想知道,这就是find在中的实现方式;哪个列表继承

override /*IterableLike*/
  def find(p: A => Boolean): Option[A] = {
    var these = this
    while (!these.isEmpty) {
      if (p(these.head)) return Some(these.head)
      these = these.tail
    }
    None
  }

如果您想使用
for
循环,它使用的语法比
.find
.filter
等的链式调用更好,有一个巧妙的技巧。与其迭代严格的集合(如列表),不如迭代惰性集合(如迭代器或流)。如果您从严格的集合开始,请使用使其惰性ode>.toIterator

让我们看一个例子

首先,让我们定义一个“noise”int,它将在调用时显示出来

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
…意味着所有元素都被访问。这是有意义的,因为结果列表包含所有偶数。这次让我们在迭代器上迭代:

val r2 = (for(e <- l.toIterator; val v = e() ; if v % 2 == 0) yield v)
请注意,循环仅在能够确定结果是空迭代器还是非空迭代器时执行

要获得第一个结果,现在只需调用
r2.next

如果您想要
选项的结果
类型,请使用:

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

编辑此编码的第二个示例如下:

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

这是一个可怕的黑客。但是它会得到你想要的结果

习惯上,您会使用流或视图,只计算所需的部分

def findFirst[T](objects: List[T]): T = {

def expensiveFunc(o : T)  = // unclear what should be returned here

case class MissusedException(val data: T) extends Exception

try {
  (for (obj <- objects) {
    if (expensiveFunc(obj) != null) throw new MissusedException(obj)
  })
  objects.head // T must be returned from loop, dummy
} catch {
  case MissusedException(obj) => obj
}
def findFirst[T](对象:列表[T]):T={
def expensiveFunc(o:T)=//不清楚这里应该返回什么
案例类误用异常(val数据:T)扩展了异常
试一试{
(用于(obj obj)
}
}我希望能帮助你

我认为…没有“回报”意味着

object TakeWhileLoop extends App {
    println("first non-null: " + func(Seq(null, null, "x", "y", "z")))

    def func[T](seq: Seq[T]): T = if (seq.isEmpty) null.asInstanceOf[T] else
        seq(seq.takeWhile(_ == null).size)
}

object OptionLoop extends App {
    println("first non-null: " + func(Seq(null, null, "x", "y", "z")))

    def func[T](seq: Seq[T], index: Int = 0): T = if (seq.isEmpty) null.asInstanceOf[T] else
        Option(seq(index)) getOrElse func(seq, index + 1)
}

object WhileLoop extends App {
    println("first non-null: " + func(Seq(null, null, "x", "y", "z")))

    def func[T](seq: Seq[T]): T = if (seq.isEmpty) null.asInstanceOf[T] else {
        var i = 0
        def obj = seq(i)
        while (obj == null)
            i += 1
        obj
    }
}

诀窍是在collection上获得一些惰性的求值视图,可以是迭代器或流,也可以是objects.view。过滤器将只在需要时执行。

您可以将列表转换为流,以便for循环包含的任何过滤器都只按需求值。但是,从流中生成的过滤器将始终返回一个流,即d您想要的是我假设一个选项,因此,作为最后一步,您可以检查结果流是否至少有一个元素,并将其head作为选项返回

def findFirst[T](objects: List[T], expensiveFunc: T => Boolean): Option[T] =
    (for (obj <- objects.toStream if expensiveFunc(obj)) yield obj).headOption
def findFirst[T](对象:List[T],expensiveFunc:T=>Boolean):选项[T]=
(对于(obj为什么不

object Main {     
  def main(args: Array[String]): Unit = {
    val seven = (for (
    x <- 1 to 10
    if x == 7
    ) yield x).headOption
  }
}
objectmain{
def main(参数:数组[字符串]):单位={
val seven=(用于(

x代码示例正是从
for
循环返回单个元素。您想做什么不同的操作?将返回类型更改为
选项[T]
你写的代码会有用的。我不确定我是否理解你的问题。我建议你使用
find
版本,同时避免使用
null
return
使你的代码更符合Scala的习惯。完全同意Jesper的观点。你的问题听起来像是:是的,我知道如何在conc中解决这个问题ise和显而易见的方式,但有人能教我如何使这个问题变得单一和复杂吗?对于这个问题,没有比基于“find.Return from closures”的方法更好的解决方案了。这很接近,是否可以这样编写,以便返回的值的类型实际上是单个Int,而不是向量[Int]或列表[Int]?在我的示例中,结果类型是一个
迭代器
。调用
。下一步
获取
Int
(如果没有解决方案,将抛出异常)。我明白了……是否有一个方法返回None而不是exception?(如果找到,则返回一些[Int])。如果没有,则可以在“Optionitor”中执行我自己的特点和隐式转换,对吗?以前有一个方法'headOpt',但它在很久以前就被弃用了。你确实可以用隐式转换自己重新定义它。这(用'if'表示理解)实际上是一个好主意,应该是第一件要考虑的事情。然而,它并不总是可能的——存在多个匹配将被创建的情况,而第二级诡计(在DaPeK的回答中提出)是对它们进行懒惰的评估。
object TakeWhileLoop extends App {
    println("first non-null: " + func(Seq(null, null, "x", "y", "z")))

    def func[T](seq: Seq[T]): T = if (seq.isEmpty) null.asInstanceOf[T] else
        seq(seq.takeWhile(_ == null).size)
}

object OptionLoop extends App {
    println("first non-null: " + func(Seq(null, null, "x", "y", "z")))

    def func[T](seq: Seq[T], index: Int = 0): T = if (seq.isEmpty) null.asInstanceOf[T] else
        Option(seq(index)) getOrElse func(seq, index + 1)
}

object WhileLoop extends App {
    println("first non-null: " + func(Seq(null, null, "x", "y", "z")))

    def func[T](seq: Seq[T]): T = if (seq.isEmpty) null.asInstanceOf[T] else {
        var i = 0
        def obj = seq(i)
        while (obj == null)
            i += 1
        obj
    }
}
objects iterator filter { obj => (expensiveFunc(obj) != null } next
def findFirst[T](objects: List[T], expensiveFunc: T => Boolean): Option[T] =
    (for (obj <- objects.toStream if expensiveFunc(obj)) yield obj).headOption
object Main {     
  def main(args: Array[String]): Unit = {
    val seven = (for (
    x <- 1 to 10
    if x == 7
    ) yield x).headOption
  }
}