我如何从一组给定的值中 select,四舍五入?

How do I select from a given set of values, rounding up?

我有一个 ruby 散列数组,其中包含两个键 'tier' 和 'price'。对于给定的价格,我想要 return 等级。

这对于精确匹配来说已经足够简单了,但是我如何通过将我的输入值四舍五入到数组中的下一个值来确保我总是匹配?

例如,给定下面的数组,如果我的值为 '499',我想 return '10'。

tiers = [
    { tier: 0, price: 0 },
    { tier: 1, price: 50 },
    { tier: 2, price: 100 },
    { tier: 3, price: 150 },
    { tier: 4, price: 200 },
    { tier: 5, price: 250 },
    { tier: 6, price: 300 },
    { tier: 7, price: 350 },
    { tier: 8, price: 400 },
    { tier: 9, price: 450 },
    { tier: 10, price: 500 },
    { tier: 11, price: 550 },
    { tier: 12, price: 600 },
    { tier: 13, price: 650 },
    { tier: 14, price: 700 },
    { tier: 15, price: 750 },
    { tier: 16, price: 800 },
    { tier: 17, price: 850 },
    { tier: 18, price: 880 },
    { tier: 19, price: 950 },
    { tier: 20, price: 1000 }
]

我可以获得与 tiers.detect { |tier| tier[:price] == "500"}[:tier] 的完全匹配,但如果我没有匹配,这将 return 出错。我可以增加我的输入值,直到我 return 匹配,但这似乎效率很低。

我考虑过四舍五入我的输入值,但您会注意到增量并不总是相同(从第 17 层到第 18 层,价格仅增加 30)。

您可以成对列举所有层级,然后根据这对层级评估您的价格。像这样:

def detect_tier(price)
  tiers.each_cons(2) do |t1, t2|
    next if price < t1[:price] # too low
    next if price > t2[:price] # too high

    return t1[:tier] if price == t1[:price] # matches tier price exactly
    return t2[:tier] # "round up"
  end
end

detect_tier(10) # => 1
detect_tier(100) # => 2
detect_tier(499) # => 10
tiers.detect{|x| x[:price] >= <required_number>}[:tier]

可以工作,如果层的结构是给定的。

虽然不处理边界条件。

tiers.detect{|x| x[:price] >= 1}[:tier] #=> 1
tiers.detect{|x| x[:price] >= 100}[:tier] #=> 2
tiers.detect{|x| x[:price] >= 499}[:tier] #=> 10
tiers.detect{|x| x[:price] >= 750}[:tier] #=> 15

如果数组很大,谨慎使用查找最小值模式 Array#bsearch_index 的方法,这会将顺序搜索的时间复杂度从 O(n) 降低到 O(log n)。

我假设 tiers 中的 :price 的值在增加,如果测试价格超过 tiers.last[:price].[=17=,则返回 nil ]

def round_up(tiers, price)
  return nil if price > tiers.last[:price]
  tiers[tiers.map { |h| h[:price] }.bsearch_index { |p| p >= price }][:tier]
end

我们来试试吧。

tiers = [
  { tier: "cat", price:   0 },
  { tier: "dog", price:  50 },
  { tier: "pig", price: 100 },
  { tier: "owl", price: 150 },
  { tier: "ram", price: 300 }
]

round_up(tiers, -10) #=> "cat"
round_up(tiers,   0) #=> "cat"
round_up(tiers,   1) #=> "dog"
round_up(tiers,  49) #=> "dog"
round_up(tiers,  50) #=> "dog"
round_up(tiers,  51) #=> "pig"
round_up(tiers, 150) #=> "owl"
round_up(tiers, 250) #=> "ram"
round_up(tiers, 300) #=> "ram"
round_up(tiers, 301) #=> nil