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)

通常の「while」、「unless」、または「each」構造の代わりに「loop do」構造を使用するのに最適な時期を誰かに説明してもらえますか?

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

そして今、「ループする」と、これは次のようになります

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

そして例外はあなたのために処理されます。また、2 つのコレクションを同時にループすることもでき、そのうちの 1 つが要素を使い果たすとすぐに、ループは正常に終了します。

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'sloopは基本的に と同じものです。実際、Rubyとほぼ同じ意味で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」もあります。

loopRuby で実際にこの問題を解決する方法はたくさんありますが、これらの複数の出口点が考えられるため、著者はこの構造を選択したのでしょう。与えられたソリューション コードは、他のすべての可能性よりも優れているとは限りません。

于 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

'loop' コンストラクトを使用した loop は、ブロック内のコードが特定の条件で壊れるまで、指定されたブロックを無限に実行します。

ループするコレクションがない場合、「each」と「for」が機能しない場所で使用できます。

「ループ」と while/until の違いは、特定の条件が満たされたときに while/until が指定されたブロックを実行することです。ループの場合と同様に、開始する条件がなく、条件はループのブロック内にあります。

理解を深めるために、ドキュメントを読んでください。

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

于 2013-05-29T12:28:08.440 に答える