25

I would like to use something like reverse_each_with_index on an array.

Example:

array.reverse_each_with_index do |node,index|
  puts node
  puts index
end

I see that Ruby has each_with_index but it doesn’t seem to have an opposite. Is there another way to do this?

2
  • Could you tell me what the output you want to have? Commented Apr 1, 2013 at 6:03
  • Are you asking how to use an (non-)existing method called reverse_each_with_index, or want to implement one that has a certain function? Different portions of your question imply one or the other. Commented Apr 1, 2013 at 6:20

7 Answers 7

58

If you want the real index of the element in the array you can do this

['Seriously', 'Chunky', 'Bacon'].to_enum.with_index.reverse_each do |word, index|
  puts "index #{index}: #{word}"
end

Output:

index 2: Bacon
index 1: Chunky
index 0: Seriously

You can also define your own reverse_each_with_index method

class Array
  def reverse_each_with_index &block
    to_enum.with_index.reverse_each &block
  end
end

['Seriously', 'Chunky', 'Bacon'].reverse_each_with_index do |word, index|
  puts "index #{index}: #{word}"
end

An optimized version

class Array
  def reverse_each_with_index &block
    (0...length).reverse_each do |i|
      block.call self[i], i
    end
  end
end
Sign up to request clarification or add additional context in comments.

1 Comment

This is the only variant except for (array.size - 1).downto(0) that lets you delete_at(index) during enumeration. The other solutions at the time of me writing this will not produce stable indices.
21

First reverse the array, and then use each_with_index:

array.reverse.each_with_index do |element, index|
  # ...
end

Although, indexes will go from 0 to length - 1, not the other way around.

2 Comments

this creates a copy of the array, doesn't it?
It certainly does.
11

Without copying array:

(array.size - 1).downto(0) do |index|
  node = array[index]
  # ...
end

2 Comments

By far the fastest way! Sometimes old plain integer iterations are better than fancy iterators. ;-)
Yeah I think this is best so far. It's really a shame ruby doesn't have a more intuitive way.
9

Well since Ruby always likes to give you options you can not only do:

arr.reverse.each_with_index do |e, i|

end

but you can also do:

arr.reverse_each.with_index do |e, i|

end

2 Comments

I'd expect .reverse_each.with_index to be faster, since .reverse_each is faster than .reverse.each. I would therefore use .reverse_each.with_index and reverse the indexes myself, or use the reversed index as a negative array lookup. Although brief experimentation did not show a big difference in my irb.
arr.reverse_each.with_index do |e, i| end doesn't work for what the op is asking for. This will yield the forward ordered indexes [0,1,2 etc]
2

Simply

arr.reverse.each_with_index do |node, index|

Comments

2

The real correct answer is like the following.

a = ['a', 'b', 'c']
a.each_with_index.reverse_each {|e, i|
  p [i, e]
}

This gives the following output.

[2, "c"]
[1, "b"]
[0, "a"]

As a side note, this has worked on Ruby 1.9.3(around 2011) and later at least.

3 Comments

This needs to be the accepted answer. Clean, to the point, and (probably) highly performant.
Did anyone test this for performance? I wonder if this is reversing something in there.
The merit of this answer is brevity and readability. This will create a temporary array, so it will be slower than the answer of Pavel Evstigneev.
0

in my usecase I wanted to iterate backwards using negative indexes

a = %w[a b c] 
(1..a.size).each {|i| puts "-#{i}: #{a[-i]}"}
# => -1: c
# => -2: b
# => -3: a

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.