How is enum # with_object different from enum # each_with_object?
The documentation says:
Iterates the given block for each element with an arbitrary object, obj, and returns obj
Iterates the given block for each element with an arbitrary object, obj, and returns obj
But when I tried below on both constructs, one gave me the result as expected, but the others didn't. Therefore, I suspect there is a difference between the two.
Using each_with_object
%w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase }
=> {"foo"=>"FOO", "bar"=>"BAR"}
success is here!
Using with_object
%w(foo bar).with_object({}) { |str, hsh| hsh[str] = str.upcase }
=> NoMethodError: undefined method `with_object' for ["foo", "bar"]:Array
from (irb):1
from C:/Ruby193/bin/irb:12:in `<main>'
failed here!
What is the difference between these two methods?
source to share
each
returns an Enumerator object.
%w(foo bar).each.class
=> Enumerator
So, for the first case, the array is first converted to Enumerator
, then works on with_object
.
If you want the second case to work, you need to convert the array to an Enumerator. You can use .to_enum
, .each
or .map
to convert an array.
%w(foo bar).map.with_object({}) { |str, hsh| hsh[str] = str.upcase }
=> {"foo"=>"FOO", "bar"=>"BAR"}
Read more: Enumerator
source to share
with object
only works on counters, which means you need to bind it to something that returns it. eg.
%w(foo bar).each.with_object({}) { |str, h| h[str] = str.upcase }
%w(foo bar).detect.with_object(obj) { ... }
So, you can call with_object
all that returns an enumerator, if you do not give him a block (eg map
, reduce
, detect
, find_all
...). This includes anything that mixes into an Enumerable .
each_with_object
is essentially an alias for each.with_object
.
source to share