【问题标题】:Incrementing 'i' in scala for loop by differing amounts depending on circumstance根据情况在scala for循环中增加'i'不同的数量
【发布时间】:2013-09-11 10:23:43
【问题描述】:

我想在 scala 中编写一个 for 循环,但是在某些特殊情况下,计数器应该增加一个以上(数量是可变的)。

【问题讨论】:

  • val start, end, step = ???; for { i <- start to end by step}
  • 你为什么不先展示一个小作品,让我们知道你在寻求帮助之前尝试了什么。我们不是来为您工作的。
  • @senia 这不符合这里的要求。您的循环将始终以相同的数量递增,而不是可变的。
  • 您是急切地需要理解,还是只需要以某种方式循环就可以了?我问是因为它是递归的好用例。
  • 阿图尔,你可能需要至少多说一点你想要的细节,否则这将结束。

标签: scala for-loop increment


【解决方案1】:

您可以结合使用过滤器和外部变量来做到这一点。这是一个例子:

var nextValidVal = 0
for (i <- 0 to 99; if i >= nextValidVal) {
  var amountToSkip = 0
  // Whatever this loop is for
  nextValidVal = if (amountToSkip > 0) i + amountToSkip + 1 else nextValidVal
}

所以在你的循环主体中,你可以根据你的条件将amountToSkip设置为n。将跳过 i 序列的下 n 个值。

如果你的序列是从其他类型的序列中提取的,你可以这样做

var skip = 0
for (o <- someCollection if { val res = skip == 0; skip = if (!res) skip - 1 else 0; res } ) {
  // Do stuff
}

如果您在循环体中将skip 设置为正值,则将跳过该序列的下一个 n 个元素。

当然,这是非常必要且具有副作用的。我会尽可能通过映射或过滤或折叠原始序列来寻找其他方法。

【讨论】:

    【解决方案2】:

    您可以实现自己的流来反映步骤,例如:

    import scala.collection.immutable.Stream
    import ForStream._
    object Test {
      def main(args: Array[String]): Unit = {
        val range = 0 to 20 by 1 withVariableStep; // in case you like definition through range
        //val range = ForStream(0,20,1) // direct definition
        for (i<- range) {
          println(s"i=$i")
          range.step = range.step + 1
        }
      }
    }
    
    object ForStream{
      implicit def toForStream(range: Range): ForStream = new ForStreamMaster(range.start, range.end,range.step)
      def apply(head:Int, end:Int, step:Int) = new ForStreamMaster(head, end,step)
    }
    
    abstract class ForStream(override val head: Int, val end: Int, var step: Int) extends Stream[Int] {
      override val tailDefined = false
      override val isEmpty = head > end
      def withVariableStep = this
    }
    
    class ForStreamMaster(_head: Int, _end: Int, _Step: Int) extends ForStream(_head, _end,_Step){
      override def tail = if (isEmpty) Stream.Empty else new ForStreamSlave(head + step, end, step, this)
    }
    
    class ForStreamSlave(_head: Int, _end: Int, _step: Int, val master: ForStream) extends ForStream(_head, _end,_step){
      override def tail = if (isEmpty) Stream.Empty else new ForStreamSlave(head + master.step, end, master.step, master)
    }
    

    打印出来:

    i=0

    i=2

    i=5

    i=9

    i=14

    i=20

    您可以使用隐式从 Range 定义 ForStream,也可以直接定义它。但要小心:

    1. 您不再迭代 Range!
    2. Stream 应该是不可变的,但 step 是可变的!

    正如@om-nom-nom 所指出的,这可能通过递归更好地实现

    【讨论】:

    • 这假设步骤中的方差与 for 循环中的状态无关。您将如何实现它以使其在循环内可控(我认为是 OP 所要求的)。
    • 对不起,我没有明白你的意思。可通过stream.step = stream.step + 1 在循环内控制。也许 OP 应该在评估 step 时提供更多信息。
    【解决方案3】:

    为什么不使用 do-while 循环?

    var x = 0;
    do{
    ...something
    if(condition){change x to something else}
    else{something else}
    x+=1
    }while(some condition for x)
    

    【讨论】:

      猜你喜欢
      • 2012-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-15
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多