Ruby each_with_index offset
RubyIterationRuby Problem Overview
Can I define the offset of the index in the each_with_index loop iterator? My straight forward attempt failed:
some_array.each_with_index{|item, index = 1| some_func(item, index) }
Edit:
Clarification: I don't want an array offset I want that the index within the each_with_index doesn't start from 0 but e.g. 1.
Ruby Solutions
Solution 1 - Ruby
Actually, Enumerator#with_index
receives offset as an optional parameter:
[:foo, :bar, :baz].to_enum.with_index(1).each do |elem, i|
puts "#{i}: #{elem}"
end
outputs:
1: foo
2: bar
3: baz
BTW, I think it is there only in 1.9.2.
Solution 2 - Ruby
The following is succinct, using Ruby's Enumerator class.
[:foo, :bar, :baz].each.with_index(1) do |elem, i|
puts "#{i}: #{elem}"
end
output
1: foo
2: bar
3: baz
Array#each returns an enumerator, and calling Enumerator#with_index returns another enumerator, to which a block is passed.
Solution 3 - Ruby
-
The simplest is to substitute
index+1
instead ofindex
to the function:some_array.each_with_index{|item, index| some_func(item, index+1)}
but probably that is not what you want.
-
The next thing you can do is to define a different index
j
within the block and use it instead of the original index:some_array.each_with_index{|item, i| j = i + 1; some_func(item, j)}
-
If you want to use index in this way often, then define another method:
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}"}
=>
- one
- two
- three
Update
This answer, which was answered a few years ago, is now obsolete. For modern Rubies, Zack Xu's answer will work better.
Solution 4 - Ruby
If some_index
is somehow meaningful, then consider using a hash, rather than an array.
Solution 5 - Ruby
I ran into it.
My solution not necessary is the best, but it just worked for me.
In the view iteration:
just add: index + 1
That's all for me, as I don't use any reference to those index numbers but just for show in a list.
Solution 6 - Ruby
Yes, you can
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
Also I should notice that if offset is more than your Array size it will though an error. Because:
some_array[1000,-1] => nil
nil.each_with_index => Error 'undefined method `each_with_index' for nil:NilClass'
What can we do here:
(some_array[offset..-1]||[]).each_with_index{|item, index| some_func(item, index) }
Or to prevalidate offset:
offset = 1000
some_array[offset..-1].each_with_index{|item, index| some_func(item, index) } if offset <= some_array.size
This is little hacky
UPD 2
As far as you updated your question and now you need not Array offset, but index offset so @sawa solution will works fine for you
Solution 7 - Ruby
Ariel is right. This is the best way to handle this, and it's not that bad
ary.each_with_index do |a, i|
puts i + 1
#other code
end
That is perfectly acceptable, and better than most of the solutions I've seen for this. I always thought this was what #inject was for...oh well.
Solution 8 - Ruby
Another approach is to use 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) }
Solution 9 - Ruby
This works in every ruby version:
%W(one two three).zip(1..3).each do |value, index|
puts value, index
end
And for a generic array:
a.zip(1..a.length.each do |value, index|
puts value, index
end
Solution 10 - Ruby
offset = 2
some_array[offset..-1].each_with_index{|item, index| some_func(item, index+offset) }