How is each_with_object supposed to work?
A simple, but common example of using each_with_object
is when you need to build a hash depending on elements in an array. Very often you see something like:
hash = {}
[1, 2, 3, 4].each { |number| hash[number] = number**2 }
hash
Using each_with_object
avoids the explicit initialization and return of the hash
variable.
[1,2,3,4].each_with_object({}) { |number, hash| hash[number] = number**2 }
I advise reading the docs for inject
, tap
, and each_with_index
. These methods are helpful when you aim for short and readable code.
each_with_object
does not work on immutable objects like integer.
(1..3).each_with_object(0) {|i,sum| sum += i} #=> 0
This is because each_with_object
iterates over a collection, passing each element and the given object to the block. It does not update the value of object after each iteration and returns the original given object.
It would work with a hash since changing value of a hash key changes it for original object by itself.
(1..3).each_with_object({:sum => 0}) {|i,hsh| hsh[:sum] += i}
#=> {:sum => 6}
String
objects are interesting case. They are mutable so you might expect the following
to return "abc"
("a".."c").each_with_object("") {|i,str| str += i} # => ""
but it does not. This is because str += "a"
returns a new object and the original object stays the same. However if we do
("a".."c").each_with_object("") {|i,str| str << i} # => "abc"
it works because str << "a"
modifies the original object.
For more info see ruby docs for each_with_object
For your purpose, use inject
(1..3).inject(0) {|sum,i| sum += i} #=> 6
# or
(1..3).inject(:+) #=> 6