Rubyeach_with_indexオフセット


84

each_with_indexループイテレータでインデックスのオフセットを定義できますか?私の率直な試みは失敗しました:

some_array.each_with_index{|item, index = 1| some_func(item, index) }

編集:

明確化:配列オフセットは必要ありません。each_with_index内のインデックスが0からではなく、たとえば1から始まるようにします。


どのRubyバージョンを使用していますか?
fl00r 2011

書いていないことをお詫びしますが、私はRuby 1.9.2を使用しています
Mark

回答:


110

実際にEnumerator#with_indexは、オプションのパラメータとしてオフセットを受け取ります。

[:foo, :bar, :baz].to_enum.with_index(1).each do |elem, i|
  puts "#{i}: #{elem}"
end

出力:

1: foo
2: bar
3: baz

ところで、1.9.2にしかないと思います。


2
1.8.7ではwith_index0
パラメータ

実際には、さらに短い答えが可能です。以下の私のものを参照してください。
Zack Xu

50

以下は、Rubyの列挙子クラスを使用した簡潔なものです。

[:foo, :bar, :baz].each.with_index(1) do |elem, i|
    puts "#{i}: #{elem}"
end

出力

1: foo
2: bar
3: baz

Array#eachは列挙子を返し、Enumerator#with_indexを呼び出すと、ブロックが渡される別の列挙子が返されます。


5

1)最も簡単なのは、関数のindex+1代わりに置き換えることですindex

some_array.each_with_index{|item, index| some_func(item, index+1)}

しかし、おそらくそれはあなたが望むものではありません。

2)次にできることはj、ブロック内に別のインデックスを定義し、元のインデックスの代わりにそれを使用することです。

some_array.each_with_index{|item, i| j = i + 1; some_func(item, j)}

3)この方法でインデックスを頻繁に使用する場合は、別のメソッドを定義します。

module Enumerable
  def each_with_index_from_one *args, &pr
    each_with_index(*args){|obj, i| pr.call(obj, i+1)}
  end
end

%w(one two three).each_with_index_from_one{|w, i| puts "#{i}. #{w}"}
# =>
1. one
2. two
3. three


更新

数年前に回答されたこの回答は、現在では廃止されています。現代のルビーにとって、ザック・シューの答えはもっとうまくいくでしょう。


配列に要素がなくなった後でもイタラレするという悪いこと
fl00r 2011

@ fl00r本当に?私の例では、3分後に停止します。
さわ2011

しかし、オフセットが2または10の場合はどうでしょうか?あなたの場合、オフセットはゼロです。
つまり

@ fl00r+1コードのを+2またはに変更するだけ+10です。それも同様に機能します。
さわ2011

OMG、著者は彼の投稿を編集したので、配列ではなくインデックスオフセットが必要です。
fl00r 2011


4

私はそれに遭遇しました。

必要のない私の解決策が最善ですが、それは私にとってはうまくいきました。

ビューの反復:

追加するだけです:インデックス+ 1

これらのインデックス番号への参照は使用せず、リストに表示するためだけに使用するので、これですべてです。


3

はい、できます

some_array[offset..-1].each_with_index{|item, index| some_func(item, index) }
some_array[offset..-1].each_with_index{|item, index| some_func(item, index+offset) }
some_array[offset..-1].each_with_index{|item, index| index+=offset; some_func(item, index) }

UPD

また、オフセットが配列サイズより大きい場合、エラーが発生することに注意してください。理由:

some_array[1000,-1] => nil
nil.each_with_index => Error 'undefined method `each_with_index' for nil:NilClass'

ここで何ができるか:

 (some_array[offset..-1]||[]).each_with_index{|item, index| some_func(item, index) }

またはオフセットを事前検証するには:

 offset = 1000
 some_array[offset..-1].each_with_index{|item, index| some_func(item, index) } if offset <= some_array.size

これは少しハッキーです

UPD 2

質問を更新し、配列オフセットは必要ありませんが、インデックスオフセットが必要なため、@ sawaソリューションは問題なく機能します。


1

アリエルは正しい。これはこれを処理するための最良の方法であり、それほど悪くはありません

ary.each_with_index do |a, i|
  puts i + 1
  #other code
end

これは完全に受け入れられ、これについて私が見たほとんどのソリューションよりも優れています。私はいつもこれが#injectの目的だと思っていました...まあ。


1

別のアプローチは使用することです map

some_array = [:foo, :bar, :baz]
some_array_plus_offset_index = some_array.each_with_index.map {|item, i| [item, i + 1]}
some_array_plus_offset_index.each{|item, offset_index| some_func(item, offset_index) }

1

これはすべてのルビーバージョンで機能します:

%W(one two three).zip(1..3).each do |value, index|
  puts value, index
end

そして、ジェネリック配列の場合:

a.zip(1..a.length.each do |value, index|
  puts value, index
end

2番目の例では角かっこがありません。
ウェーハシン2015年

0
offset = 2
some_array[offset..-1].each_with_index{|item, index| some_func(item, index+offset) }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.