From: Intransition Date: 2010-10-08T07:34:52+09:00 Subject: Re: "map" a deeply nested structure: Object#deep_map On Oct 7, 1:18 pm, Guido De Rosa wrote: > That way you can say for example: > >     Here's a deeply nested object; replace any "content" n which is a >     Fixnum with the number 123 > > But you cannot say: > >     Here's a deeply nested object; replace any "content" n which is a >     Fixnum with the number n + 1 > > #deep_replace would be a lot more flexible if replacement could be a > lambda. > > The drawback is that client code would look ugly: > >     o.deep_replace(lambda {|x| x+1}) {|y| ...} > > Is there an elegant way o pass *two* blocks of code? Indeed there is. In fact that is something akin to how the new Facets #recursively method works. arr = ["a", ["b", "c"]] arr.recursively{ |a| a.reverse }.map{ |v| v.to_sym } #=> [:a, [:c, :b]] The first block handles enumerables and the second handles non- enumerable elements. (See http://github.com/rubyworks/facets/blob/master/lib/core/facets/array/recursively.rb) But I am not sure #recursively can help in the search-and-replace case. This leads me to wonder about a more general API, e.g. def match(&match) Enumerable::Matcher.new(&match) end And then Enumerable::Matcher could have different methods for what to do with the various matches, such as #replace or #delete. > Maybe a more consistent API would look like: > >     o.deep_replace( >       lambda {|x| ... }, # matching conditions >       lambda {|x| ... }  # replacement code >     ) > > or like: > >     o.deep_replace( >       lambda {|k, v| ...                }, # matching conditions >       lambda {|k, v| ... [new_k, new_v] }  # replacement code >     ) > > But more simply the "matching" may be done by the client code: > >    o.deep_replace do |k, v| >      if matching_conditions(k, v) >        # do the replecement >        ... >        [new_k, new_v] >      else >        [k, v] # leave the same >      end >    end > > so, again, we have to pass one block of code, but for the replacement, > not the match. But we still have the problem of matching |k,v| for Hashes but |e| for Arrays.