在Ruby中使用多参数记忆函数

在Ruby中使用多参数记忆函数,ruby,memoization,Ruby,Memoization,我想知道是否有一种更“类似于Ruby”的方法可以在Ruby中记忆具有多个参数的函数。我想出了一个可行的方法,但不确定这是否是最好的方法: @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

我想知道是否有一种更“类似于Ruby”的方法可以在Ruby中记忆具有多个参数的函数。我想出了一个可行的方法,但不确定这是否是最好的方法:

@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

这些参数用逗号连接,逗号用作存储在
@cache
变量中的键。

您可以直接使用数组:

def area(length, width)
  key = [length, width]
  if @cache[key]
    puts 'cache hit!'
    return @cache[key]
  end
  @cache[key] = length * width
end
或使用嵌套哈希:

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

当您不需要打印
缓存时,点击然后我会这样做:

def area(length, width)
  @cache ||= {}
  @cache["#{length},#{width}"] ||= length * width
end
def area(*args)
  @cache ||= {}
  @cache[args] ||= args.inject(:*)
end
或者如果您需要一些输出,但是
缓存未命中也可以:

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

  @cache.fetch("#{length},#{width}") do |key| 
    puts 'Cache miss!'
    @cache[key] = length * width
  end
end
如果您想要接受更多的参数,您可能需要使用如下内容:

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

在Ruby 2.7及更高版本上,位置参数和关键字参数是隔离的,这对如何实现多参数记忆有影响。对于一般实现,我将执行以下操作:

def area(length, width)
  @cache ||= {}
  @cache["#{length},#{width}"] ||= length * width
end
def area(*args)
  @cache ||= {}
  @cache[args] ||= args.inject(:*)
end
def my_方法(*args,**kwargs)
(@my_method_cache | |={})[args.hash^kwargs.hash]| |=开始
(...)
结束
结束

(…)
替换为使用
我的_方法所做的昂贵计算

我会对所有这些方法的线程安全性感到紧张,但尤其是最后一个。第一个方法的妙招。那么数组会自动转换为字符串吗?线程到底有什么问题?什么会出错?将生成两种不同的缓存数据结构?不,数组不会自动转换为字符串。没有必要这样做。因为每个对象都可以用作哈希键:符号、整数,甚至是庞大复杂的数据结构。。。但是使用嵌套的哈希表,一个调用可以清除不同宽度的计算(对于相同的长度),例如,我做了一些基准测试。我原来使用连接的函数的速度是使用对象作为键的速度的两倍。有没有一种自动生成密钥的好方法?即使去掉print语句,您的代码也比我的代码快2倍。您的意思是,如果您使用常用命名参数,但不想全部列出它们?也许有个办法:看看这个。但我会用它…我想它应该是硬编码的。那看起来很难看。有处理多参数记忆的Ruby gem吗?如果性能有问题,散列参数并使用整数作为键会更好。类似于
length.hash^width.hash
。它还可以很容易地适应于处理可变数量的参数:
args.inject{| r,n | r^n.hash}
。哈希冲突的可能性非常小。你总是可以加入一个素数来降低这些几率。