将一系列数字转换为条件/范围

时间:2013-02-22 13:25:09

标签: ruby conditional range

我有一个由数字和一些值组成的数组:

a = [[2, :foo], [5, :bar], ..., [17, :baz]]

其中可以假设没有两对具有相同的数字,并且这些对按其数字的值排序。基于此数组a,我想传递一个数字i,它始终位于a中的最小和最大数字之间,并返回与数字配对的值是最大的不超过i的。一些预期的回报值是:

2 # => :foo
4 # => :foo
5 # => :bar
17 # => :baz

最好的方法是什么?使用散列在处理范围作为键时存在问题,并且使用case语句很难动态采用a

3 个答案:

答案 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.