我不喜欢为范围中的每个可能项创建单独的键/值对的想法。这样做完全不可扩展,尤其是对于广泛的范围。考虑这个小范围:
'a' .. 'zz'
这将导致702个额外的键。尝试('a'..'zz').to_a
进行有趣的操作。继续吧,我等着。
不要创建这些键,拦截查找。重用RangedHash
类名:
class RangedHash < Hash
def [](key)
return self.fetch(key) if self.key? key
self.keys.select{ |k| k.is_a? Range }.each do |r_k|
return self.fetch(r_k) if r_k === key
end
nil
end
end
foo = RangedHash.new
foo[1] = [6,2,2]
foo[2] = [7,4,5]
foo[3..7] = [7,2,1]
此时foo
的样子如下:
{1=>[6, 2, 2], 2=>[7, 4, 5], 3..7=>[7, 2, 1]}
测试该方法:
require 'pp'
3.upto(7) do |i|
pp foo[i]
end
这将产生以下输出:
[7, 2, 1]
[7, 2, 1]
[7, 2, 1]
[7, 2, 1]
[7, 2, 1]
对于范围内的任何值,此函数输出与该范围相关联的值。在哈希中定义但超出范围的值会正常工作,对于哈希中不存在的键,返回
nil
也是如此。而且,它使哈希尽可能小。
这种方法或任何解决方案的缺点是,范围键可能重叠,导致冲突。在大多数提出的解决方案中,键会互相覆盖,这可能会导致返回错误的值。这种方法不会这样做,因为需要直接冲突才能覆盖范围键。
要修复这个问题,需要决定是否允许重叠,如果允许,则第一个找到的是否可以返回,或者应该有逻辑来确定“最佳匹配”,即适合的最小范围,或完全不同的一些标准。或者,如果值相同,应将重叠的部分合并为更大的范围吗?这是一个麻烦的问题。