如何在Ruby中重构巨大的查找表

时间:2016-01-31 16:29:25

标签: ruby-on-rails ruby

我有一个方法:

def assign_value
   ...
   @obj.value = find_value
end

和一个巨大的查找表:

def find_value
   if @var > 0 && @var <= 30
      0.4
   elsif @var > 30 && @var <= 50
      0.7
   elsif @var > 50 && @var <= 70
      1.1
   elsif @var > 70 && @var <= 100
      1.5
   elsif @var > 100 && @var <= 140
      2.10
   elsif @var > 140 && @var <= 200
      2.95
   elsif @var > 200 && @var <= 300
      4.35
   elsif @var > 300 && @var <= 400
      6.15
   elsif @var > 400 && @var <= 500
      7.85
   elsif @var > 500 && @var <= 600
      9.65
   ...

end

依此类推1800行。

毋庸置疑,这是一个未命名国家的税务部门。现在,它是手动编写的(所有1800行),以计算整数范围和十进制返回值的变化长度。

如果不重写整个国家/地区的税码,我该怎么重构呢?

范围和值每年都会发生变化,我们需要保持向后兼容性。数据库表可以简化问题,但由于我们正在处理许多不同的国家/地区,每个国家都有不同的要求和税码,因此创建数据库表并不像听起来那么简单。

3 个答案:

答案 0 :(得分:3)

@ MilesStanfield的答案与你的答案几乎相同。正如我在评论中所说,我会使用散列来摆脱所有条件(或案例):

COUNTRY_TAX_RATES = {
  0..30 => 0.4,
  31..50 => 0.7,
  51..70 => 1.1
}

COUNTRY_TAX_RATES[0..30] # 0.4
COUNTRY_TAX_RATES.select { |code| code === 10 }.values.first # 0.4

如果您不经常更改代码,则可以使用此代码。如果它经常更改,您可以考虑使用其他方法(例如,存储在db中并通过用户界面进行管理)。

更新:现在我不再在我的手机上了,我想进一步扩展这个答案。你似乎无视@Wand Maker的提议,但我认为你不应该这样做。

想象一下你使用我的哈希。它方便,没有任何条件,易于调整。但是,正如Wand Maker所指出的那样,每次更改范围或十进制时,您都需要开发人员更新代码。这可能没问题,因为你只需要每年进行一次,但这不是最干净的方法。

您希望会计师能够更新税率和代码,而不是开发人员。所以你应该创建一个包含这些属性的表。我不确定你的例子中的范围和小数是什么,但我希望你明白这个想法:

Tax (ActiveRecord) with range_column (Give this an explicit, explanatory name. You could also use min and max range columns), code, rate and country_id

class Tax < ActiveRecord::Base
  serialize :range_column

  belongs_to :country
end

Country has_many :taxes

如果您想知道马耳他(country_id:30)的税率,使用税码40(无论这可能意味着什么),您可以这样做:

Tax.select(:tax_rate).joins(:country).find_by(country_id: 30, range_column: 40).tax_rate # you might need a between statement instead, can't check right now if querying a serialized hash works like this

现在,会计师可以在更改时更新范围,小数或任何其他属性(当然,您必须先为其构建CRUD)。

P.S。不要介意命名,不确定这些数字代表什么。 :)

答案 1 :(得分:1)

我会使用范围

的case语句
case @var
when 0..30 then 0.4
when 31..50 then 0.7
when 51..70 then 1.1
...
end

答案 2 :(得分:1)

假设inc是收入而arr是一对数组[bp, tax],其中

  • arr[0][0] = 0,意为bp(收入&#34;断点&#34;)arr的第一个元素为零;
  • arr[i][0] < arr[i+1][0],意思是断点正在增加;
  • 如果arr[-1][1],则需支付
  • inc >= arr[-1][0];和
  • 如果arr[i][1]arr[i][0] <= inc < arr[i+1][0]。,则需支付
  • 0 <= i <= arr.size-2

然后可以计算税收

arr.find { |bp,_| inc >= bp }.last

因为断点正在增加。