Skip to content

Instantly share code, notes, and snippets.

@mdunsmuir
Created May 6, 2013 22:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mdunsmuir/5528672 to your computer and use it in GitHub Desktop.
Save mdunsmuir/5528672 to your computer and use it in GitHub Desktop.
Hash subclass for Numeric keys only, returns either the actual value for an existing key, the values for the lower and upper *bounding* keys respectively for a bounded unknown key, or the value for the greatest or smallest existing key in the case of an out-of-bounds unknown key.
#
# This subclass of Hash is designed to search for the values associated
# with the two nearest Numeric keys to a given "key" argument *not*
# a member of the FindNeighborsHash, or the *single* value associated with
# an *existing* key.
#
class FindNeighborsHash < Hash
def []=(key, val)
raise ArgumentError.new("key must be Numeric") unless key.is_a? Numeric
@sortedkeys = nil
super
end
def [](key)
raise ArgumentError.new("key must be Numeric") unless key.is_a? Numeric
sortkeys() unless @sortedkeys
first = 0; last = @sortedkeys.size - 1
arr = @sortedkeys.clone
while last - first > 0
mid = first + (last - first) / 2
if key > arr[mid]
first = mid + 1
else
last = mid
end
end
neighbors = [arr[first]]
if key > arr[first]
neighbors << arr[first + 1] if arr[first + 1]
elsif key < arr[first]
neighbors << arr[first - 1] if first > 0
end
return self.values_at(*neighbors.sort)
end
private
def sortkeys(); @sortedkeys = self.keys.sort; end
end
require 'minitest/autorun'
require File.join(File.dirname(__FILE__), 'find_neighbors_hash')
describe FindNeighborsHash do
before do
@fnh = FindNeighborsHash.new
@arr = [1, 3, 45, 234, 34, 5, 78, 345, 4523, 7, 878]
@arr.each_with_index{ |val, i|
@fnh[val] = i
}
end
it "must raise an ArgumentError when keyed with a non-Numeric" do
assert_raises(ArgumentError){ @fnh["hello"] = 2 }
assert_raises(ArgumentError){ @fnh["goodbye"] }
end
it "must return the correct bounding values for an unknown bounded key" do
assert_equal(@fnh[40.3], [4, 2])
assert_equal(@fnh[2], [0, 1])
assert_equal(@fnh[357], [7, 10])
end
it "must return the correct values for unknown out-of-range keys" do
assert_equal(@fnh[-5], [0])
assert_equal(@fnh[50000], [8])
end
it "must return the correct values for known keys" do
assert_equal(@fnh[1], [0])
assert_equal(@fnh[878], [@arr.size - 1])
assert_equal(@fnh[45], [2])
assert_equal(@fnh[78], [6])
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment