each vs map in Ruby: what is the difference?

Short answer

each returns the original collection and is for side effects. map returns a new array built from whatever the block returned.

ruby
languages = ["python", "ruby", "php"]

languages.each { |l| puts l.capitalize }   # prints; returns the ORIGINAL array
languages.map  { |l| l.capitalize }        # ["Python", "Ruby", "Php"]

#The pattern to recognise

ruby
result = []
languages.each { |l| result << l.upcase }

That is map written the long way. Three lines become one:

ruby
result = languages.map(&:upcase)

Whenever you see each pushing into an accumulator array, it wants to be map.

#The &: shorthand

map(&:upcase) is shorthand for map { |x| x.upcase }. It works with any method that takes no arguments — &:to_i, &:strip, &:even?.

#Use each when there is nothing to build

ruby
users.each { |u| send_email(u) }

Here map would build an array of return values you do not want. That is misleading to read and pointless to allocate.

#The bang versions mutate

ruby
languages.map! { |l| l.upcase }   # changes languages in place, returns it

Reach for map! rarely. Returning a new collection keeps functions easier to reason about.