0

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]

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

4 Comments

@user3281384 No worries. Good question!
rotate good spot. Although the each {|e| e} seem superfluous to requirements in both your examples.
ah yeah, that makes sense, my bad.
@sagarpandya82 No worries!
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.