【问题标题】:How to break from a nested loop to a parent loop that is more than one level above which requires a value provided by the nested loop如何从嵌套循环中断到高于一级以上需要嵌套循环提供的值的父循环
【发布时间】:2016-12-26 22:48:56
【问题描述】:

以下情况:

xxx.delete_if do |x|
  yyy.descend do |y| # This is a pathname.descend
    zzz.each do |z|
      if x + y == z
        # Do something

        # Break all nested loops returning to "xxx.delete_if do |x|" loop

        # The "xxx.delete_if do |x|" must receive a "true" so that it
        # can delete the array item
      end
    end
  end
end

在确保我可以传递true 值以便删除数组项的同时实现这种多重嵌套中断的最佳方法是什么?

也许我应该使用多个返回 truebreak 语句,或者使用带有变量的 throw/catch,但我不知道这些是否是最佳答案。


这个问题与How to break from nested loops in Ruby? 不同,因为它要求父循环从嵌套循环中接收一个值。

【问题讨论】:

  • 当有人提出一个可以通过 Google 搜索轻松找到的问题时,它会收到很多赞成票,但当它是非常具体且很难找到的问题时,它就会被反对。

标签: ruby nested each break


【解决方案1】:

您可以使用多个break 语句。

例如:

xxx.delete_if do |x|
  result = yyy.each do |y|
    result2 = zzz.each do |z|
      if x + y == z
         break true
      end
    end
    break true if result2 == true
  end
  result == true
end

但是,在您的特定情况下,我绝对会避免这种情况。

您不应该将变量分配给each 的结果。改用mapreduceselectrejectany?all?

使用any? 来实现同样的目的更有意义:

xxx.delete_if do |x|
  yyy.any? do |y|
    zzz.any? do |z|
      x + y == z
    end
  end
end

【讨论】:

  • 我并不难使用any?,它工作正常,但在我的具体情况下,其中一个循环是path.descend,所以它确实需要使用变量。我将使用descend 更新问题。
  • 其实有一种方法,就我而言,不使用变量,我只是切换了最后两个循环,所以最后一个是yyy.descend do |y|,这样我只需要添加里面有一个break true,一切正常。谢谢。
【解决方案2】:

throw/catch(不是raise/rescue)是我通常看到的完成方式。

xxx.delete_if do |x|
  catch(:done) do
    yyy.each do |y|
      zzz.each do |z|
        if x + y == z
          # Do something

          throw(:done, true)
        end
      end
    end
    false
  end
end

其实the Pickaxe明确推荐的:

虽然 raise 和 rescue 的异常机制非常适合在出现问题时放弃执行,但有时能够在正常处理期间跳出一些深度嵌套的构造也很不错。这就是catch and throw派上用场的地方。当 Ruby 遇到 throw 时,它会拉回调用堆栈以寻找具有匹配符号的 catch 块。当它找到它时,Ruby 将堆栈展开到该点并终止该块。如果使用可选的第二个参数调用 throw,则该值作为 catch 的值返回。

也就是说,max 的#any? 建议更适合这个问题。

【讨论】:

  • 问题是delete_if需要true来删除数组元素。在提出问题之前,我已经尝试过您的解决方案。
  • 您当时没有尝试使用throw 的可选第二个参数,因为我的解决方案有效。 :)
  • 我记得我也尝试过,但没有成功,因为我尝试了许多不同的解决方案,我会再试一次,看看它是否有效,也许我做错了什么。
  • 效果很好,我可能做错了什么,但我选择了另一个答案,因为它更短,而且我没有注意到性能上有任何差异。
猜你喜欢
  • 1970-01-01
  • 2013-01-29
  • 1970-01-01
  • 1970-01-01
  • 2019-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多