2

私はRubyを初めて使用し、曜日を出力してから1日をループで削除する非常に単純なアプリケーションを作成しました。

def print_days(days)
    days.each do |day|
        print "The day of the week is: #{day}\n"
        days.delete(day)
        print "\n*****************************************************\n"
        print days
        print "\n*****************************************************\n"
    end
end

wd = %w[Monday Tuesday Wednesday Thursday Friday Saturday Sunday]

print print_days(wd

これにより、実行時に次の出力が得られます。各要素を順番に削除していて、配列がそこにあることを示しているときに、火曜日、木曜日、土曜日がスキップされる理由を誰か説明できますか? セットアップでこの簡単なコードを実行できます。

The day of the week is: Monday

*****************************************************
["Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
*****************************************************
The day of the week is: Wednesday

*****************************************************
["Tuesday", "Thursday", "Friday", "Saturday", "Sunday"]
*****************************************************
The day of the week is: Friday

*****************************************************
["Tuesday", "Thursday", "Saturday", "Sunday"]
*****************************************************
The day of the week is: Sunday

*****************************************************
["Tuesday", "Thursday", "Saturday"]
*****************************************************
["Tuesday", "Thursday", "Saturday"]
4

4 に答える 4

4

配列を反復処理しているときに配列から要素を削除し、イテレータを無効にします。

あなたは試すことができます

   until (days.empty?) 
       day = days.shift
       print "The day of the week is: #{day}\n"
   end

また

   days.each{|day| print "The day of the week is: #{day}\n"}
   days.clear
于 2013-01-18T20:58:45.550 に答える
3

すべての要素の反復中に配列を変更しています。内部的に、 each メソッドは、ブロックに渡された最後のアイテムのインデックスを保持しています。これは基本的にイテレータを無効にしています。他の言語では例外がスローされます。

Ruby はそうではありません。

したがって、最初はインデックス 0 の要素が生成されます。

次に、インデックス 0 の要素を削除します

その後、次回はインデックス 1 の要素が生成されます。現在はインデックス 0 であるため、火曜日は基本的にスキップされます。

于 2013-01-18T21:00:15.723 に答える
2

基本ルールを破りました。反復しているオブジェクトを反復している間は、そのオブジェクトを変更しないでください。

ここで何が起こっているのですか:

  1. 配列を反復処理する
  2. 最初の項目から始めます
  3. 最初のアイテムを削除
  4. 配列の 2 番目の項目が最初の項目になりました。
  5. 2 番目のアイテムを取得します。前の 2 番目のアイテムが 1 番目になったため、以前は3 番目のアイテムだったものが取得されます。
  6. 変更された配列の 2 番目の項目 (以前は 3 番目だった) を削除します

そのため、他のすべてのアイテムの削除をスキップします。これらのタイプの奇妙なバグは、反復しているオブジェクトを反復している間に変更することが非常に嫌われる理由です。そうしないでください。

しかし、あなたの例がどれほど不自然であるかを考えると、より良い方法を提案することは困難です. 実際の目標に応じて、これを行うためのより良い方法があります。

于 2013-01-18T21:02:25.767 に答える
0

上記の回答のほとんどが、あなたがやっていることの失敗の理由を説明していることを考えると、

Array#drop_while
Array#delete_if
Array#select!

また

Array#keep_if

例えば

a=[1,2,3,4]
a.drop_while{|e| puts e; true}

与える

1
2
3
4
 => []
于 2013-01-18T22:53:27.037 に答える