David said:
Hi --
------------------------------------------------- Enumerator#with_object
e.with_object(obj) {|(*args), memo_obj| ... }
e.with_object(obj)
From Ruby 1.9.1
------------------------------------------------------------------------
Iterates the given block for each element with an arbitrary object
given, and returns the initially given object.
If no block is given, returns an enumerator.
That's pretty much what it does. It's kind of like inject, except it
uses the same object each time through instead of assigning the
accumulator slot to the value of the block. Thus:
array = [1,2,3,4,5]
tens_hash = array.each_with_object({}) {|n,obj| obj[n] = n * 10 }
# => {1=>10, 2=>20, 3=>30, 4=>40, 5=>50}
It saves you having to do that awkward:
{|h,n| h[n] = n * 10; h }
thing to feed the object back into the loop.
Without a block, it returns an enumerator, which will then do a
"with"-style double iteration (like with_index) based on whatever you
call on it:
array = [1,2,3,4,5] => [1, 2, 3, 4, 5]
enum = array.each_with_object({})
=> # said:
tens_hash = enum.each {|n,obj| obj[n] = n * 10 }
=> {1=>10, 2=>20, 3=>30, 4=>40, 5=>50}
David
David said:
Hi --
------------------------------------------------- Enumerator#with_object
e.with_object(obj) {|(*args), memo_obj| ... }
e.with_object(obj)
From Ruby 1.9.1
------------------------------------------------------------------------
Iterates the given block for each element with an arbitrary object
given, and returns the initially given object.
If no block is given, returns an enumerator.
That's pretty much what it does. It's kind of like inject, except it
uses the same object each time through instead of assigning the
accumulator slot to the value of the block. Thus:
array = [1,2,3,4,5]
tens_hash = array.each_with_object({}) {|n,obj| obj[n] = n * 10 }
# => {1=>10, 2=>20, 3=>30, 4=>40, 5=>50}
It saves you having to do that awkward:
{|h,n| h[n] = n * 10; h }
thing to feed the object back into the loop.
Without a block, it returns an enumerator, which will then do a
"with"-style double iteration (like with_index) based on whatever you
call on it:
array = [1,2,3,4,5] => [1, 2, 3, 4, 5]
enum = array.each_with_object({})
=> # said:
tens_hash = enum.each {|n,obj| obj[n] = n * 10 }
=> {1=>10, 2=>20, 3=>30, 4=>40, 5=>50}
David
Thanks for the response.
In the definition:
e.with_object(obj) {|(*args), memo_obj| ... }
1) Why *args?
2) Why (*args) ?
My tests show the first argument that with_object yields to the block
may or may not be an array:
example a:
----------
class A
def my_iter
yield "red", 1
yield "blue", 2
end
end
a = A.new
a.my_iter{|x, y| puts "#{x} #{y}"}
--output:--
red 1
blue 2
(That shows that the yield sends two arguments to the block--not an
array.)
h = {}
results = e.with_object(h) do |args, _|
p args
end
--output:--
["red", 1]
["blue", 2]
example b:
---------
class A
def my_iter
yield 1
yield 2
end
end
a = A.new
a.my_iter{|x| puts "#{x}"}
--output:--
1
2
e = a.enum_for
my_iter)
h = {}
results = e.with_object(h) do |args, _|
p args
end
--output:--
1
2
======
In the definition:
e.with_object(obj) {|(*args), memo_obj| ... }
3) Why 'memo_obj' and not 'obj'?
Even though two different variable names makes it hard to track what is
going on, the following assignment takes place:
memo_obj = obj
For example:
e = a.enum_for
my_iter)
h = {}
puts "#{h.inspect} #{h.object_id}"
results = e.with_object(h) do |args, accumulator_hash|
key, val = args
accumulator_hash[key] = val
print "#{accumulator_hash.inspect}"
puts " #{accumulator_hash.object_id}"
end
--output:--
{} 345296
{"red"=>1} 345296
{"red"=>1, "blue"=>2} 345296
In the description:
------------------------------------------------- Enumerator#with_object
e.with_object(obj) {|(*args), memo_obj| ... }
e.with_object(obj)
From Ruby 1.9.1
------------------------------------------------------------------------
Iterates the given block for each element with an arbitrary object
given, and returns the initially given object.
If no block is given, returns an enumerator.
----------------------------------------------------
there needs to be a little more detail. Maybe something like:
Yields element_of_e, obj to the block. args will be an array when e is
attached to an iterator that yields more than one value, otherwise args
will be the value the iterator yields. The return value of the block is
discarded.
If a block is given, with_object returns memo_obj. If no block is
given, with_object returns an enumerator.
Here's a full example that I played around with:
class A
def my_iter
yield "red", 1
yield "blue", 2
end
end
a = A.new
a.my_iter{|x, y| puts "#{x} #{y}"}
--output:--
red 1
blue 2
e = a.enum_for
my_iter)
h = {}
puts "#{h.inspect} #{h.object_id}"
--output:--
{} 345212
results = e.with_object(h) do |args, accumulator_hash|
p args
key, val = args
accumulator_hash[key] = val
print "#{accumulator_hash.inspect}"
puts " #{accumulator_hash.object_id}"
10
end
--output:--
["red", 1]
{"red"=>1} 345212
["blue", 2]
{"red"=>1, "blue"=>2} 345212