Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memoizing functions with multiple parameters in Ruby

I'm wondering if there is a more "Ruby-like" way to memoize functions with multiple parameters in Ruby. Here's a way that I came up with that works but not sure if it's the best approach:

@cache = {}
def area(length, width)  #Just an example, caching is worthless for this simple function
  key = [length.to_s, width.to_s].join(',')
  if @cache[key]
    puts 'cache hit!'
    return @cache[key]
  end
  @cache[key] = length * width
end

puts area 5, 3
puts area 5, 3
puts area 4, 3
puts area 3, 4
puts area 4, 3

The parameters are joined with a comma which is then used as a key for storage in the @cache variable.

like image 383
StevieD Avatar asked Dec 05 '22 11:12

StevieD


2 Answers

When you do not need to print Cache hit! than I would do something like this:

def area(length, width)
  @cache ||= {}
  @cache["#{length},#{width}"] ||= length * width
end

Or if you need some output, but a Cache miss! is fine too:

def area(length, width)
  @cache ||= {}

  @cache.fetch("#{length},#{width}") do |key| 
    puts 'Cache miss!'
    @cache[key] = length * width
  end
end

If you want to accept even more arguments you might want to use something like this:

def area(*args)
  @cache ||= {}
  @cache[args] ||= args.inject(:*)
end
like image 122
spickermann Avatar answered Jan 06 '23 23:01

spickermann


You can use the array directly:

def area(length, width)
  key = [length, width]
  if @cache[key]
    puts 'cache hit!'
    return @cache[key]
  end
  @cache[key] = length * width
end

Or use nested hashes:

def area(length, width)
  c = (@cache[length] ||= {})
  if c[width]
    puts 'cache hit!'
    return c[width]
  end
  c[width] = length * width
end
like image 30
matthewd Avatar answered Jan 06 '23 21:01

matthewd