【问题标题】:How do I select from a given set of values, rounding up?如何从给定的一组值中进行选择,四舍五入?
【发布时间】:2018-01-26 02:11:00
【问题描述】:

我有一个带有两个键“tier”和“price”的红宝石哈希数组。对于给定的价格,我想退回该层级。

使用精确匹配很简单,但是如何通过将输入值向上舍入到数组中的下一个值来确保我总是匹配?

例如,给定下面的数组,如果我有一个值 '499',我想返回 '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] 的完全匹配,但如果我没有匹配,这将返回错误。我可以增加我的输入值,直到我返回一个匹配,但这似乎非常低效。

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

【问题讨论】:

    标签: ruby math hashtable


    【解决方案1】:

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

    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
    

    【讨论】:

    • 是的,这就是诀窍。我仍在尝试理解这里的逻辑,但这似乎正是我所追求的!
    • @NickBarreto:阅读each_cons 上的文档,这是解决方案的核心
    • 是的,这真的很有用。谢谢! @SergioTulentsev
    【解决方案2】:
    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
    

    【讨论】:

    • 使用detect 而不是select.first
    • Prakash,如果您同意@Sergio 的观点,即首选detect(又名find)(我愿意),我建议您修改答案以删除select 答案。通常,您只会通过包含不太理想的解决方案来削弱您的答案。您最初没有使用 detect 的事实是无关紧要的。另外,为了保持你的答案干净,如果你想感谢 Sergio,我建议你在评论中这样做。我可能会这样写:“谢谢,塞尔吉奥,这样更好。我进行了编辑。读者:我以前写过……”。
    • @CarySwoveland:我自己说得再好不过了 :)
    【解决方案3】:

    如果数组很大,最好使用 find-minimum 模式 Array#bsearch_index 的方法,这会将时间复杂度从 O(n) 与顺序搜索降低到 O(log n)。

    我假设tiers:price 的值在增加,如果测试价格超过tiers.last[:price],则返回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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-02
      • 1970-01-01
      • 2017-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-12
      相关资源
      最近更新 更多