动态映射值范围和输出

时间:2015-12-23 03:47:44

标签: ruby

我正在尝试创建一种计算包裹运费的方法。运费来自表格,其中列出了重量范围和相应的价格。

示例数据:

0 - 50g : $1
51 - 100g : $2

我应该如何构建数据,如何根据数据动态生成价格而不是编写许多if语句?

示例代码:

def price_for_weight(w)    
  if w < 50
    return 1
  elsif w < 100
    return 2
  end

3 个答案:

答案 0 :(得分:2)

您可以这样做的一种方法是将数据结构化为Hash,并将Range个对象作为键,如下所示:

SHIPPING_COSTS = {
  0..50 => 1,
  51..100 => 2,
}

在您的方法中使用Enumerable#select,然后您可以使用===运算符获取键值对:

 def price_for_weight(w)    
    SHIPPING_COSTS.select { |range| range === w }
 end
与集合一起使用的

===会询问比较右侧的值是否可以被视为左侧集合的成员(请参阅this question)。

由于上面会返回一个键值对,你可以在块之后添加.values.first以获得成本:

 def price_for_weight(w)    
    SHIPPING_COSTS.select { |range| range === w }.values.first
 end

答案 1 :(得分:1)

假设成本并不总是全部美元,以美分计算会更好。

ShippingCost = {50 => 100, 100 => 200}

def price_for_weight(w)
  ShippingCost[ShippingCost.keys.bsearch{|k| w <= k}]
end

答案 2 :(得分:0)

以下是另一种方法:

鉴于你的范围来自DB,你将使用一些东西。我们可以使用散列来表示每个价格范围的值,如下所示。

prices = [ {min: 0, max: 50, price: 1}, {min: 50, max: 100, price: 2} ]
weight = 50.5

prices.find {|i| (i[:min]...i[:max]).include? weight }[:price]
#=> 2

另请注意范围内...的使用情况,其中不包括结束值。因此,(0...50)不会包含50。如果您使用(0..50)(50..100),或者如果您使用了(0..50)(51..100),我们就不会跳过一系列值,这样可以确保范围之间没有重叠{1}}。