如何从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
}
}