2

This question was inspired by this one: Ruby: Why does this way of using map throw an error?

Someone pointed out the following:

map doesn't make much sense when used with ! methods.

You should either:

  • use map with gsub
  • or use each with gsub!

Can someone explain why that is?

Community
  • 1
  • 1
Flip
  • 6,233
  • 7
  • 46
  • 75

2 Answers2

2

Base object

Here's an array with strings as element :

words = ['hello', 'world']

New array

If you want a new array with modified strings, you can use map with gsub :

new_words = words.map{|word| word.gsub('o','#') }

p new_words
#=> ["hell#", "w#rld"]
p words
#=> ["hello", "world"]
p new_words == words
#=> false

The original strings and the original array aren't modified.

Strings modified in place

If you want to modify the strings in place, you can use :

words.each{|word| word.gsub!('o','#') }
p words
#=> ["hell#", "w#rld"]

map and gsub!

new_words = words.map{|word| word.gsub!('o','#') }
p words
#=> ["hell#", "w#rld"]
p new_words
#=> ["hell#", "w#rld"]
p words == new_words
#=> true
p new_words.object_id
#=> 12704900
p words.object_id
#=> 12704920

Here, a new array is created, but the elements are the exact same ones!

It doesn't bring anything more than the previous examples. It creates a new Array for nothing. It also might confuse people reading your code by sending opposite signals :

  • gsub! will indicate that you want to modifiy existing objects
  • map will indicate that you don't want to modify existing objects.
Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
1

Map is for building a new array without mutating the original. Each is for performing some action on each element of an array. Doing both at once is surprising.

>> arr = ["foo bar", "baz", "quux"]
=> ["foo bar", "baz", "quux"]
>> arr.map{|x| x.gsub!(' ', '-')}
=> ["foo-bar", nil, nil]
>> arr
=> ["foo-bar", "baz", "quux"]

Since !-methods generally have side effects (and only incidentally might return a value), each should be preferred to map when invoking a !-method.

An exception might be when you have a list of actions to perform. The method to perform the action might sensibly be named with a !, but you wish to collect the results in order to report which ones succeeded or failed.

Josh Lee
  • 171,072
  • 38
  • 269
  • 275