Scala中的条件循环转换

时间:2009-10-07 10:00:07

标签: scala for-loop

我想将一段看起来如下的Java代码转换为Scala:

for (Iterator<Task> it = tasks.iterator(); it.hasNext() && workflow.isAutoRun();) {
    Task task = it.next();
    if (!runTask(task)) break;
}

我不是scala for-理解的粉丝(不是我知道如何打破迭代)并且我想出了以下内容:

val completed = tasks.forall { task => workflow.isAutoRun && runTask(task) } 

但是,forall方法的scaladoc如下所示(斜体字):

  

将谓词p 应用于此可迭代对象的所有元素并返回true,如果谓词对所有元素都为true

这与我所做的不同(因为它意味着将对每个项目评估谓词,无论先前的评估是否已返回false)和(实际上)实际上并不等同于forall方法实际上做了,Iterator看起来像:

 def forall(p: A => Boolean): Boolean = {
   var res = true
   while (res && hasNext) res = p(next)
   res
 }

无论如何,我离题了:有没有人对scala代码看起来有什么更好的建议?我希望看到更能传达意图的东西:

  

tasks.doUntil(t => !isAutoRun || !runTask(t))

5 个答案:

答案 0 :(得分:4)

在scala 2.8中,您可以执行以下操作:

breakable{
    tasks.foreach{ task =>
        if(!(workflow.isAutoRun&&runTask(task))) break
    }
}

答案 1 :(得分:4)

与Flaviu上面的答案类似,你可以在某个地方放置隐含的定义:

  implicit def conditionalLoop[T](s: Seq[T]) = {
    new {
      def doWhile(p: T => Boolean): Unit = {
        doWhile(s.elements)(p)
      }
      private def doWhile(it: Iterator[T])(p: T => Boolean): Unit = {
        if (it.hasNext && p(it.next)) doWhile(it)(p)
      }
    }
  }

然后,打电话很方便:

tasks doWhile {
  t => workflow.isAutoRun && t.run
}

答案 2 :(得分:2)

“exists”返回true,并在谓词返回true后终止循环:

val completed = tasks.exists { task =>
  if (workflow.isAutoRun) {
    runTask(task)
    false
  }
  else
    true
}

编辑:

然后试试这个:

implicit def enrichList[A](list: List[A]) = new {
  def doWhile(cond: (A) => Boolean)(body: (A) => Unit) = list exists { x =>
    if (cond(x)) {
      body(x)
      false
    }
    else
      true
  }
}

List(1, 2, 3, 4).doWhile(_ <= 3)(println) // prints "1 2 3"

tasks.doWhile(_ => workflow.isAutoRun)(runTask)

答案 3 :(得分:2)

Iterable的{​​{1}}:

怎么样?
takeWhile
     

返回此最长的前缀   可迭代的元素满足   谓词p

     

param p - 测试   谓语。

     

<强>返回    - 此迭代的最长前缀,其元素满足谓词p。

答案 4 :(得分:1)

这会有用吗?

def doWhile[T](iter: Iterator[T])(predicate: T => Boolean): Unit = 
  if(iter.hasNext && predicate(iter.next())) 
    doWhile(iter)(predicate)

它的尾部是递归的,所以它不会使堆叠爆炸。由于必须为迭代器的每个元素运行谓词,因此谓词是从TBoolean的函数。

您的代码将缩减为:

doWhile(it) {
   task => workflow.isAutoRun &&
           runTask(task)
   }

由于您的操作具有副作用,因此在评估谓词时已经执行了操作(不是很好,但如果遗留代码的工作方式如此,则必须解决它:)。

更有效的方法是:

def doWhile[T](iter: Iterator[T])(predicate: => Boolean)(action: T => Unit): Unit = 
  if(iter.hasNext && predicate) {
    action(iter.next)
    doWhile(iter)(predicate)(action) 
  }

注意:我可能会发现这个方法的名称比doWhile更好,但已经晚了......

希望有所帮助:)

- Flaviu Cipcigan