Ruby 如何从给定的一组值中进行选择,向上取整?
我有一个ruby哈希数组,有两个键,“tier”和“price”。对于给定的价格,我想返回层 这对于精确匹配来说非常简单,但是如何通过将输入值向上舍入到数组中的下一个值来确保始终具有匹配 例如,给定下面的数组,如果我的值为'499',我想返回'10'Ruby 如何从给定的一组值中进行选择,向上取整?,ruby,math,hashtable,Ruby,Math,Hashtable,我有一个ruby哈希数组,有两个键,“tier”和“price”。对于给定的价格,我想返回层 这对于精确匹配来说非常简单,但是如何通过将输入值向上舍入到数组中的下一个值来确保始终具有匹配 例如,给定下面的数组,如果我的值为'499',我想返回'10' tiers = [ { tier: 0, price: 0 }, { tier: 1, price: 50 }, { tier: 2, price: 100 }, { tier: 3, price: 150 },
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]的精确匹配,但如果我没有匹配项,这将返回一个错误。我可以增加输入值,直到返回一个匹配项,但这似乎效率很低
我考虑过将输入值四舍五入,但您会注意到,从第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
如果阵列较大,则应谨慎使用“查找最小值”模式 该方法将通过顺序搜索将时间复杂度从一开始降低到Olog n 我假设:层中的价格在增加,如果测试价格超过层,则返回nil。last[:price] 让我们试试看
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
是的,这是在耍花招。我仍在尝试探索这里的逻辑,但它确实似乎正是我所追求的@尼克巴雷托:阅读每一个问题的文档,这是解决方案的核心,是的,这非常有用。谢谢@SergioTulentsevuse detect而不是select.firstPrakash,如果您同意@Sergio的观点,即detect aka find是首选,我建议您修改您的答案以删除select答案。一般来说,你只会通过包含不太令人满意的解决方案来削弱你的答案。您最初没有使用detect这一事实与此无关。另外,为了保持你的回答清晰,如果你想感谢塞尔吉奥,我建议你在评论中这样做。我可能写过这样的话:谢谢,塞吉奥,这样更好。我做了编辑。读者:我以前写过……@CarySwoveland:我自己也说得再好不过了:
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
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