範囲内の可能なエントリごとに個別のキーと値のペアを作成するという考えは好きではありません。特に広い範囲では、まったくスケーラブルではありません。この小さな範囲を考えてみましょう:
'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
場合は、ハッシュに存在しないキーを返す場合と同様に、正常に機能します。そして、ハッシュを可能な限り小さく保ちます。
これの欠点、または質問に対する解決策は、範囲であるキーが重複して衝突を引き起こす可能性があることです。提案されたソリューションのほとんどでは、キーが互いに踏みつけられ、結果として悪い値が返される可能性があります。範囲キーを上書きするには直接競合が発生するため、このメソッドはそれを行いません。
これを修正するには、オーバーラップを許可するかどうかを決定する必要があります。許可する場合、最初に見つかったものが返されても問題ないか、または「最適」、つまり適合する最小の範囲を決定するロジックが必要か、またはいくつかの他の基準は完全に。または、値が同じ場合、オーバーラップを結合してより大きな範囲を作成する必要がありますか? ワームの缶詰です。