7

我最近遇到了一个使用 Loop Do 的问题/解决方案。到目前为止,我在学习 Ruby 编程时很少看到这一点(我是一个没有 CS 经验的初学者)。

# Write a function, `nearest_larger(arr, i)` which takes an array and an
# index.  The function should return another index, `j`: this should
# satisfy:
#
# (a) `arr[i] < arr[j]`, AND
# (b) there is no `j2` closer to `i` than `j` where `arr[i] < arr[j]`.
#
# In case of ties (see example beow), choose the earliest (left-most)
# of the two indices. If no number in `arr` is largr than `arr[i]`,
# return `nil`.
#
# Difficulty: 2/5

describe "#nearest_larger" do
  it "handles a simple case to the right" do
    nearest_larger([2,3,4,8], 2).should == 3
  end

  it "handles a simple case to the left" do
    nearest_larger([2,8,4,3], 2).should == 1
  end

  it "treats any two larger numbers like a tie" do
    nearest_larger([2,6,4,8], 2).should == 1
  end

  it "should choose the left case in a tie" do
    nearest_larger([2,6,4,6], 2).should == 1
  end

  it "handles a case with an answer > 1 distance to the left" do
    nearest_larger([8,2,4,3], 2).should == 0
  end

  it "handles a case with an answer > 1 distance to the right" do
    nearest_larger([2,4,3,8], 1).should == 3
  end

  it "should return nil if no larger number is found" do
    nearest_larger( [2, 6, 4, 8], 3).should == nil
  end
end

解决方案

def nearest_larger(arr, idx)
  diff = 1
  loop do
    left = idx - diff
    right = idx + diff

    if (left >= 0) && (arr[left] > arr[idx])
      return left
    elsif (right < arr.length) && (arr[right] > arr[idx])
      return right
    elsif (left < 0) && (right >= arr.length)
      return nil
    end

    diff += 1
  end
end
 nearest_larger([2,4,3,8], 1)

有人可以向我解释什么时候是使用“loop do”构造而不是通常的“while”或“unless”或“each”构造的最佳时间?

4

5 回答 5

25

加上前面的答案,

当使用外部迭代器时,“loop do”结构还提供了更简洁的语法,例如

没有“循环做”

my_iterator = (1..9).each
begin
  while(true)
    puts my_iterator.next
  end
rescue StopIteration => e
  puts e
end

现在有了“loop do”,这将变成

my_iterator = (1..9).each
loop do
  puts my_iterator.next
end

并且为您处理异常。它还允许您同时循环遍历两个集合,并且一旦其中一个用完元素,循环就会优雅地退出,

iterator = (1..9).each
iterator_two = (1..5).each

loop do
  puts iterator.next
  puts iterator_two.next
end

它将打印:1,1,2,2,3,3,4,4,5,5,6。

更多信息请访问:ruby-docs.org

于 2013-10-10T04:11:30.090 回答
16

在没有 的语言中loop,您可以使用while如下构造:

while( true ) {
  # Do stuff until you detect it is done
  if (done) break;
}

关键是您在不知道要执行多少次迭代的情况下开始循环(或者很难提前计算),但是很容易检测到循环应该何时结束。此外,对于特定情况,您可能会发现等效的while (! done) { # do stuff }语法很笨拙,因为 done 条件可能发生在循环的中途或多个地方。

Ruby与 Rubyloop基本上是一样的while( true )——事实上你while( true )几乎可以和它互换使用。

在给定的示例中,每次迭代中有以下返回点:

if (left >= 0) && (arr[left] > arr[idx])
  return left   # <-- HERE
elsif (right < arr.length) && (arr[right] > arr[idx])
  return right  # <-- HERE
elsif (left < 0) && (right >= arr.length)
  return nil    # <-- HERE
end 

如果没有满足结束条件,这里还有一个隐含的“else continue looping”。

这些多个可能的退出点大概是作者选择该loop构造的原因,尽管在实践中使用 Ruby 有很多方法可以解决这个问题。给定的解决方案代码不一定优于所有其他可能性。

于 2013-05-29T12:08:54.467 回答
3

使用该loop do构造可以让您打破条件。

例如:

i=0
loop do
  i+=1
  print "#{i} "
  break if i==10
end 

当您知道将要处理的元素数量时,您会想要使用它,类似于for each循环

于 2013-05-29T11:58:48.170 回答
2

带有“循环”结构的循环将无休止地执行给定的块,直到块内的代码在特定条件下中断。

当您没有要循环的集合时,可以使用它,“each”和“for”无法工作的地方。

'loop' 和 while/until 的不同之处在于 while/until 将在满足特定条件时执行给定的块,而在循环的情况下,没有条件开始,条件位于循环的块内。

为了更好地理解阅读文档。

http://www.ruby-doc.org/core-1.9.2/Kernel.html#method-i-loop

于 2013-05-29T12:28:08.440 回答
0

假设您想放置多个条件,将它们放在一起可能会更整洁。取而代之的是,例如:

x = 0
while x <= 10
    num = gets.to_f

    break if num < 1
    break if /\D/.match? num.to_s

    puts num ** 2
end

将中断分组在一起使其更具可读性

x = 0
loop do
    num = gets.to_f

    break if num < 1
    break if x <= 10
    break if /\D/.match? num.to_s

    puts num ** 2
end
于 2019-09-12T11:41:05.047 回答