How to map/collect with index in Ruby?

RubyArraysIndexing

Ruby Problem Overview


What is the easiest way to convert

[x1, x2, x3, ... , xN]

to

[[x1, 2], [x2, 3], [x3, 4], ... , [xN, N+1]]

Ruby Solutions


Solution 1 - Ruby

If you're using ruby 1.8.7 or 1.9, you can use the fact that iterator methods like each_with_index, when called without a block, return an Enumerator object, which you can call Enumerable methods like map on. So you can do:

arr.each_with_index.map { |x,i| [x, i+2] }

In 1.8.6 you can do:

require 'enumerator'
arr.enum_for(:each_with_index).map { |x,i| [x, i+2] }

Solution 2 - Ruby

Ruby has Enumerator#with_index(offset = 0), so first convert the array to an enumerator using Object#to_enum or Array#map:

[:a, :b, :c].map.with_index(2).to_a
#=> [[:a, 2], [:b, 3], [:c, 4]]

Solution 3 - Ruby

In ruby 1.9.3 there is a chainable method called with_index which can be chained to map.

For example:

array.map.with_index { |item, index| ... }

Solution 4 - Ruby

Over the top obfuscation:

arr = ('a'..'g').to_a
indexes = arr.each_index.map(&2.method(:+))
arr.zip(indexes)

Solution 5 - Ruby

I have always enjoyed the syntax of this style:

a = [1, 2, 3, 4]
a.each_with_index.map { |el, index| el + index }
# => [1, 3, 5, 7]

Invoking each_with_index gets you an enumerator you can easily map over with your index available.

Solution 6 - Ruby

Here are two more options for 1.8.6 (or 1.9) without using enumerator:

# Fun with functional
arr = ('a'..'g').to_a
arr.zip( (2..(arr.length+2)).to_a )
#=> [["a", 2], ["b", 3], ["c", 4], ["d", 5], ["e", 6], ["f", 7], ["g", 8]]

# The simplest
n = 1
arr.map{ |c| [c, n+=1 ] }
#=> [["a", 2], ["b", 3], ["c", 4], ["d", 5], ["e", 6], ["f", 7], ["g", 8]]

Solution 7 - Ruby

A fun, but useless way to do this:

az  = ('a'..'z').to_a
azz = az.map{|e| [e, az.index(e)+2]}

Solution 8 - Ruby

a = [1, 2, 3]
p [a, (2...a.size+2).to_a].transpose

Solution 9 - Ruby

module Enumerable
  def map_with_index(&block)
    i = 0
    self.map { |val|
      val = block.call(val, i)
      i += 1
      val
    }
  end
end

["foo", "bar"].map_with_index {|item, index| [item, index] } => [["foo", 0], ["bar", 1]]

Solution 10 - Ruby

I often do this:

arr = ["a", "b", "c"]

(0...arr.length).map do |int|
  [arr[int], int + 2]
end

#=> [["a", 2], ["b", 3], ["c", 4]]

Instead of directly iterating over the elements of the array, you're iterating over a range of integers and using them as the indices to retrieve the elements of the array.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMisha MoroshkoView Question on Stackoverflow
Solution 1 - Rubysepp2kView Answer on Stackoverflow
Solution 2 - RubytoklandView Answer on Stackoverflow
Solution 3 - RubyfruqiView Answer on Stackoverflow
Solution 4 - RubyAndrew GrimmView Answer on Stackoverflow
Solution 5 - RubyyburyugView Answer on Stackoverflow
Solution 6 - RubyPhrogzView Answer on Stackoverflow
Solution 7 - RubyAutomaticoView Answer on Stackoverflow
Solution 8 - RubyNikolay BobrovskiyView Answer on Stackoverflow
Solution 9 - RubyMo WadView Answer on Stackoverflow
Solution 10 - RubygrandineroView Answer on Stackoverflow