0

["H", "A", "L"].collect {|x| x.succ } # => ["I", "B", "M"] but

["H", "A", "L"].each {|x| x.succ } # => ["H", "A", "L"]

What is causing the difference in output here?

The succ method increments a string.

lampShade
  • 4,361
  • 8
  • 34
  • 50

2 Answers2

6

The result of the block in Array#each are completely discarded, the result of each is the array itself (that's why you get the original ["H","A","L"]). Here you want a collect/map as you show in the first snippet (which creates a new array and leaves the old one untouched).

The output of each is discarded because each is the classical imperative for-loop: you need to do some kind of side-effect (read from a file, print to screen, update an array/hash, ...) to effectively do something.

My advice is to avoid each unless there is a good reason for it. I mean, it's ok to use each to write lines to a file, for example, but never to emulate a map, select, inject, or other FP abstractions.

tokland
  • 66,169
  • 13
  • 144
  • 170
  • would you explain a little more, why is the output discarded with Enumerable#each? – lampShade Nov 03 '11 at 18:45
  • That's the way it works. Use `each` when you're interested in the operation; use `collect` or its synonym `map` when you're interested in the output. Read the docs for more info. – Marnen Laibow-Koser Nov 03 '11 at 18:54
1

An alternate approach using each_char:

"HAL".each_char.map {|x| x.succ } # => ["I", "B", "M"]

or just map

["H","A","L"].map {|x| x.succ } # => ["I", "B", "M"]

Cheers :)

Sean Vikoren
  • 1,084
  • 1
  • 13
  • 24