From: Robert Klemme Date: 2010-10-07T00:13:46+09:00 Subject: Re: "map" a deeply nested structure: Object#deep_map On Wed, Oct 6, 2010 at 4:43 PM, Guido De Rosa wrote: > Hi, > > most of you probably know/use Ruby Facets > > http://rubyworks.github.com/facets/ > > I've recently posted a question on Facets discussion group: > > http://groups.google.com/group/facets-universal/browse_thread/thread/683215a35f06af36 > > and I also tried my implementation (which apparently works fine): > > http://snurl.com/19n6qh > >    class Object > >      def deep_map(&block) >        if self.respond_to? :each_pair >          out = {} >          self.each_pair do |k, v| >            out[k] = v.deep_map(&block) What about keys? Hash#map allows to map keys and values irb(main):001:0> h={1=>2,3=>4} => {1=>2, 3=>4} irb(main):002:0> h.map {|k,v| [k*10,v*100]} => [[10, 200], [30, 400]] What, if the key is an Array or Hash? Wouldn't this be more appropriate? out[k.deep_map(&block)] = v.deep_map(&block) OTOH then you cannot map key and value together. >          end >          return out >        elsif self.respond_to? :each >          out = [] >          self.each do |x| >            out << x.deep_map(&block) >          end >          return out >        else >          return block.call(self) >        end >      end > >    end > > > Is there room for improvements? Facets author suggested to start a > discussion here too. You could remove lines "out = ..." and replace them by out = self.class.new > So: what is, in your opinion, the best way to map a deeply nested > structure made up of Arrays, Hashes, Array of Hashes etc. etc. ? I wonder how many use cases for this there are actually. In your example you can uniformly treat each object since you want the object_id. That would work for a few other methods as well (e.g. #inspect, #to_s). In other cases you would have to discriminate treatment of leave values in your block, e.g. x.deep_map |y| case y when String ... when Fixnum ... else ... end That list could become lengthy. Basically you implemented tree traversal with double dispatch - only that the double dispatch must be done manually in the block. :-) Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/