Reputation: 531
I'd like to iterate over an entire array, starting from any position. I'm not sure if there's a way to achieve this easily in Ruby, and I couldn't find any examples in the Array
or Enumerator
docs.
array = [0, 1, 2, 3, 4]
array.each.starting_at(3) { |e| e }
#=> [3, 4, 0, 1, 2]
And also:
array.each.starting_at_reverse(3) { |e| e }
#=> [3, 2, 1, 0, 4]
Upvotes: 0
Views: 769
Reputation: 53
You can do this with upto
and downto
Fixnum's methods:
array = [0, 1, 2, 3, 4]
last_index = array.size - 1
3.upto last_index do |i|
puts array[i]
end
# => 3, 4
last_index.downto 3 do |i|
puts array[i]
end
# => 4, 3
PS. as speed benchmark, iteration with rotation faster
array.rotate(3).each {|e| puts e}
benchmark:
require 'benchmark'
array = Array.new(10000000) { rand(1...9) }
last_index = array.size - 1
Benchmark.bm do |x|
x.report 'upto' do
10000.upto last_index do |index| a = array[index] + 1; end
end
x.report 'downto' do
last_index.downto 10000 do |index| a = array[index] + 1; end
end
x.report 'rotate' do
array.rotate(10000).each {|e| a = e + 1 }
end
end
# RESULTS:
# user system total real
# upto 0.680000 0.000000 0.680000 ( 0.681932)
# downto 0.680000 0.000000 0.680000 ( 0.679752)
# rotate 0.590000 0.040000 0.630000 ( 0.622901)
but, as memory benchmark, iteration by array indexes less memory hungry, especially on big array sizes:
require 'memory_profiler'
array = Array.new(10000000) { rand(1...9) }
last_index = array.size - 1
{
upto: -> { 10000.upto last_index do |index| a = array[index] + 1; end },
downto: -> { last_index.downto 10000 do |index| a = array[index] + 1; end },
rotate: -> { array.rotate(10000).each {|e| a = e + 1 } },
reverse_rotate: -> { array.reverse.rotate(10000).each {|e| a = e + 1 } }
}.each { |desc, code| puts "#{desc.to_s} => #{MemoryProfiler.report(&code).total_allocated_memsize.to_s}" }
# RESULTS (in bytes):
# upto => 0 # no additional memory allocation
# downto => 0 # no additional memory allocation
# rotate => 80000040 # implicitly copied array 1 time
# reverse_rotate => 160000080 # implicitly copied array 2 times
Upvotes: 0
Reputation: 7308
You can use the rotate
method for this. This method rotates the position of each element by n
. So your examples can be done like this
array.rotate(3).each {|e| e }
and
array.reverse.rotate(1).each {|e| e}
Note: for the second method the parameter to rotate can be derived by finding the negative index of n
. So for this the element at index 3
is at index -2
in a length 5
array.
Upvotes: 2