我有一个由数字和一些值组成的数组:
a = [[2, :foo], [5, :bar], ..., [17, :baz]]
其中可以假设没有两对具有相同的数字,并且这些对按其数字的值排序。基于此数组a
,我想传递一个数字i
,它始终位于a
中的最小和最大数字之间,并返回与数字配对的值是最大的不超过i
的。一些预期的回报值是:
2 # => :foo
4 # => :foo
5 # => :bar
17 # => :baz
最好的方法是什么?使用散列在处理范围作为键时存在问题,并且使用case
语句很难动态采用a
。
答案 0 :(得分:5)
如果您想要对数复杂度,则需要使用二分搜索或某种平衡搜索树。为简单起见,我建议使用rbtree
gem:
require 'rbtree'
a = [[2, :foo], [5, :bar], [17, :baz]]
t = RBTree[a]
t.upper_bound 4 # => [2, :foo]
t.upper_bound 5 # => [5, :bar]
t.upper_bound 1 # => nil
答案 1 :(得分:3)
即将到来的Range#bsearch
的完美工作:-)这样你就可以获得正确的日志复杂性。
bsearch
设置为在您想要最大值时找到最小值,因此您需要反转数组。享受:
DATA = [[2, :foo], [5, :bar], [12, :hello], [17, :baz]].reverse
def lookup(i)
nb, val = DATA.bsearch{|nb, val| i >= nb}
val
end
lookup 2 # => :foo
lookup 4 # => :foo
lookup 5 # => :bar
lookup 17 # => :baz
今天可以使用require 'backports/2.0.0'
: - )
答案 2 :(得分:1)
我没有真正解决你使用哈希的问题,但如果我理解正确,这可以正常工作。
a = [[2, :foo], [5, :bar], [17, :baz]]
h = Hash[a]
class Hash
def get(i)
return nil if i < keys.min
i -= 1 until include?(i)
self[i]
end
end
h.get(4) #=> :foo
h.get(5) #=> :bar
h.get(1) #=> nil # No key below 2 exists.