513

What is the easiest way to convert

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

to

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

10 Answers 10

931

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] } 
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks! Could you give me a pointer to documentation for .each_with_index.map ?
@Misha: map is a method of Enumerable as always. each_with_index, when called without a block, returns an Enumerator object (in 1.8.7+), which mixes in Enumerable, so you can call map, select, reject etc. on it just like on an array, hash, range etc.
IMO this is simpler and better-reading in 1.8.7+: arr.map.with_index{ |o,i| [o,i+2] }
@Phrogz: map.with_index doesn't work in 1.8.7 (map returns an array when called without a block in 1.8).
Important to note this doesn't work with .map! if you want to directly affect the array you're looping on.
|
308

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]] 

1 Comment

I believe this is the better answer, because it will work with map! foo = ['d'] * 5; foo.map!.with_index { |x,i| x * i }; foo #=> ["", "d", "dd", "ddd", "dddd"]
216

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| ... } 

Comments

20

Over the top obfuscation:

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

1 Comment

Andrew must have great job security! :)
14

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.

1 Comment

9

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]] 

Comments

4

A fun, but useless way to do this:

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

4 Comments

Why the hate? It is a functioning way of doing this AND I even say that is is a silly way to achieve the results.
the call to #index means this is now an O(N^2) loop also why the +2 ? :)
As I write A fun, but useless way. +2 is to create the output the OP asks for
Fun and useless is different from "really inefficient and poor programming practice"
3
a = [1, 2, 3] p [a, (2...a.size+2).to_a].transpose 

Comments

2
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]] 

1 Comment

This might be an easier way to go for 1.8.6 and 1.8.7 (yes some of us still use it) instead of having to use weirder stuff like each_with_index.map etc. and even those of us on newer versions might prefer it to having to use map.with_index FWIW :)
1

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.

2 Comments

If you read the other answers, I hope you now realise there are better approaches. So not sure why you needed to add this.
If Andrew Grimm's answer deserves ten votes, then this one deserves at least one!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.