On Fri, Apr 9, 2010 at 8:02 PM, Caleb C. [email protected] wrote:
Why is it flattening the result?
To just make that much stranger:
[1, 2, 3, [‘a’, ‘b’, ‘c’] ].visit.with_index{ |x,i| i }
=> [0, 1, 2, [3, 4, 5]]
Doesn’t flatten, but somehow the index is being carried on to the
subarray iterations – that really fracks with my mind.
This has got to be a bug. It should at least either flatten or not
flatten consistently.
I’m not sure that it is a bug.
http://www.ruby-doc.org/ruby-1.9/classes/Enumerable.html#M002713
enum.map {| obj | block } => array
Returns a new array with the results of running block once for every
element in enum.
http://www.ruby-doc.org/ruby-1.9/classes/Enumerable.src/M002713.html
static VALUE
enum_collect(VALUE obj)
{
VALUE ary;
RETURN_ENUMERATOR(obj, 0, 0);
ary = rb_ary_new();
rb_block_call(obj, id_each, 0, 0, collect_i, ary);
return ary;
}
The following is Intransition’s methods with some added info.
It looks to me as though two things are happening.
-
Using #map inside #visit combined with using Enumerable#map
seems to (within #visit) produce the structure of the original array,
but with nil values instead of the original values.
(Changing #map inside #visit to #each gets back the original values.)
-
Irrespective of the internal results from #visit, Enumerable#map
collects the successive results of the block for Enumerable#map
into a new (flat) array.
module Enumerable
def visit(&block)
puts “#=> Enumerable#visit: self=0x#{self.object_id}= #{self.inspect}”
if block_given? then result = map do |e| e.visit(&block) end
else result = to_enum(:visit)
end
puts “#=> Enumerable#visit: result=0x#{result.object_id}=
#{result.inspect}”
result
end
end
class Object
def visit(&block) ; block.call(self) ; end
end
arr = [ 10, [ 210 ], 30 ]
it = arr.visit
#=> Enumerable#visit: self=0x13928400= [10, [210], 30]
#=> Enumerable#visit: result=0x13927776= #Enumerator:0x1a90ac0
puts ; rr = it.each{ |x| x+7 }
#=> Enumerable#visit: self=0x13928400= [10, [210], 30]
#=> Enumerable#visit: self=0x13928416= [210]
#=> Enumerable#visit: result=0x1562576= [217]
#=> Enumerable#visit: result=0x13926848= [17, [217], 37]
puts “#=> rr=0x#{rr.object_id}= #{rr.inspect}”
#=> rr=0x13926848= [17, [217], 37]
puts ; rr = it.map{ |x| x+7 }
#=> Enumerable#visit: self=0x13928400= [10, [210], 30]
#=> Enumerable#visit: self=0x13928416= [210]
#=> Enumerable#visit: result=0x1559360= [nil]
#=> Enumerable#visit: result=0x1559840= [nil, [nil], nil]
puts “#=> rr=0x#{rr.object_id}= #{rr.inspect}”
#=> rr=0x1561088= [17, 217, 37]
Note that the last Enumerable#visit result from it.map
has the same structure as the original nested array
(albeit with nil values - dunno why at the moment),
but that the return value of it.map is a flat array
of the successive results of the block calculation.
Changing:
if block_given? then result = map do |e| e.visit(&block) end
to:
if block_given? then result = each do |e| e.visit(&block) end
gives for it.map:
puts ; rr = it.map{ |x| x+7 }
#=> Enumerable#visit: self=0x14484864= [10, [210], 30]
#=> Enumerable#visit: self=0x14484896= [210]
#=> Enumerable#visit: result=0x14484896= [210]
#=> Enumerable#visit: result=0x14484864= [10, [210], 30]
puts “#=> rr=0x#{rr.object_id}= #{rr.inspect}”
#=> rr=0x1298112= [17, 217, 37]