-1

While each does not change the values of a given row in a 2d array (unlike map):

test_array = [[0,0],[0,0],[0,0]]

test_array[0].each {|e| e = 1}
test_array # => [[0, 0], [0, 0], [0, 0]]

test_array[0].map! {|e| e = 1}
test_array # => [[1, 1], [0, 0], [0, 0]]

each changes the values of a given column (in a way different from map):

test_array = [[0,0],[0,0],[0,0]]

test_array.each {|row| row[0] = 2} 
test_array # => [[2, 0], [2, 0], [2, 0]]

test_array.map! {|row| row[0] = 2}
test_array # => [2, 2, 2]

Can somebody explain what is happening?

sawa
  • 165,429
  • 45
  • 277
  • 381
Joe
  • 1
  • 1
  • `each` makes sense, but the question is why does `map!` replace each internal array with a `2` whereas `map` (without the `!` operator) returns `[[2,0],[2,0],[2,0]]`. – Sagar Pandya Nov 15 '15 at 14:31

1 Answers1

3

That's because, in Ruby, parameters are 'passed by object reference'.

In the case below,

test_array.each {|row| row[0] = 2}

row refers to an array inside test_array, and modifying its contents will reflect in test_array. This mutates the sub-array present in test_array.

In the case below,

test_array[0].each {|e| e = 1}

e refers to an integer in array[0], and making it point to a different integer will not impact the original value as we are not mutating the integer values present in array[0].

More details here: Is Ruby pass by reference or by value?

Regarding your query on map, please note that you are using map!, which will mutate the object on which the method is called, whereas map returns the value.

map! {|item| block } → ary

Invokes the given block once for each element of self, replacing the element with the value returned by the block.

Output of map is returned as is:

test_array.map {|row| row[0] = 2}
test_array # => [[2, 0], [2, 0], [2, 0]]

test_array is replaced with output of map:

test_array.map! {|row| row[0] = 2}
test_array # => [2, 2, 2]
Community
  • 1
  • 1
Wand Maker
  • 18,476
  • 8
  • 53
  • 87