Andrew Kim
Andrew Kim

Reputation: 3335

Why does map enumerable return value not return expected value

I'm pretty familiar with the Ruby Enumerable module, or at least so I thought. Take the following code snippet:

names = [ "Donald", "Daisy", "Daffy" ]

new_empty_array = []

new_names_array = names.map do |name|
  new_empty_array << name
end

puts new_names_array.inspect
# prints [["Donald", "Daisy", "Daffy"], ["Donald", "Daisy", "Daffy"], ["Donald", "Daisy", "Daffy"]]

I know I'm not using map correctly, but I was teaching a lesson on Ruby enumerables and came across this example when a student was testing map out. The return value of the shovel (<<) operator is the array after an element has been added. Shouldn't the result instead be:

[["Donald"], ["Donald", "Daisy"], ["Donald", "Daisy", "Daffy"]]

It seems that the entire loop processes and the final return value of the shovel operator is processed? What gives?

Upvotes: 3

Views: 144

Answers (2)

peter
peter

Reputation: 42182

new_names_array = first_names.map do |name|
  name
end

would give ["Donald", "Daisy", "Daffy"].

Each element of first_names returns a value to the new array created by map but instead you return for each element a new array, new_empty_array.

This object is << three times and at the end has the three names, so 3 x 3 elements:

[new_empty_array, new_empty_array, new_empty_array] = [["Donald", "Daisy", "Daffy"], ["Donald", "Daisy", "Daffy"], ["Donald", "Daisy", "Daffy"]]

Upvotes: 0

Wand Maker
Wand Maker

Reputation: 18762

The result of map, in your case, is an array which consists of references to same array new_empty_array multiple times. You are not creating three different arrays, but modifying the same array in the map block.

To get the output you are expecting, you need to do:

new_names_array = first_names.map do |name|
  (new_empty_array << name).dup
end

As a side note, you could use this code, which is more obvious than the code above, for the output you desire:

(1..first_names.size).map do |num|
  first_names.take(num)
end
#=> [["Donald"], ["Donald", "Daisy"], ["Donald", "Daisy", "Daffy"]]

Upvotes: 5

Related Questions