Created
May 6, 2013 22:14
-
-
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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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