Search code examples
arraysrubyenumerable

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?


Solution

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