From: Robert Klemme Date: 2009-05-02T23:25:02+09:00 Subject: Re: lazy lookup On 02.05.2009 15:33, Thomas Hafner wrote: > Hello, > > how about the following implementation for lazy lookups? > > def define_lookup > h = lambda{ |k| > h = {} > # ... fill h (expensive!) ... > h[k] > } > self.class.class_eval{ define_method(:lookup){ |k| h[k] } } > end > > Once ``define_lookup'' has been called, the method ``lookup'' is > defined and will act in a lazy manner. Just call ``lookup'' as often > as you need, but only for the first time the expensive operation (e.g. > dealing with files) will be performed. Due to duck typing no condition > needs to be checked: for the first call ``h[k]'' implies calling the > lambda, for the next times ``h[k]'' implies accessing the hash. > > (Tried with Ruby 1.8.6.) Sorry to sound discouraging but there is memoize already. The difference is that not the whole Hash is filled but only the one that you need for the argument list provided which seems potentially more efficient. define_lookup should probably be a class method but in that case having a single Hash for all instances is problematic. Note, that you can use Hash's default_proc to achieve something similar very elegantly: class Foo def initialize(some, args) @some = some @args = args @lookup = Hash.new {|h,k| h[k] = do_lookup(k)} end def lookup(a,b) @lookup[[a,b]] end private def do_lookup(args) puts "calculating..." sleep 2 args.first + args.last + @some + @args end end Note that you do not need a separate method but if the calculation is complex code might be more readable with another method. irb(main):059:0> f = Foo.new 1,2 => # irb(main):060:0> f.lookup 3,4 calculating... => 10 irb(main):061:0> f.lookup 3,4 => 10 irb(main):062:0> In case you want to fill the Hash completely you can just replace the calculation code to assign multiple values. OTOH, often a single Hash with a default_proc is sufficient already, e.h. irb(main):064:0> foo = Hash.new {|h,k| h[k] = k + 1 + 3} => {} irb(main):065:0> foo[3] => 7 irb(main):066:0> foo => {3=>7} Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/