使重复的 if/else 或 case 语句更干
Making repetitive if/else or case statements more DRY
我经常发现自己的 if/else 语句在与不同的值进行比较时基本上重复了同一行。在这里,我正在编写代码来预测致命流感爆发造成的死亡人数。它已被重构为一个 case 语句,仍然很 WET:
def predicted_deaths(population_density, population, state)
case
when population_density >= 200 then number_of_deaths = (population * 0.4).floor
when population_density >= 150 then number_of_deaths = (population * 0.3).floor
when population_density >= 100 then number_of_deaths = (population * 0.2).floor
when population_density >= 50 then number_of_deaths = (population * 0.1).floor
else number_of_deaths = (population * 0.05).floor
end
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
我试着找一些东西和
一起工作
j = 0.4
i = 200
until i <= 50 do
@population_density >= i then number_of_deaths = (@population * j).floor
i -= 50
j -= 0.1
end
但这并没有真正做同样的事情。
如何使重复的 case 语句更干?
编辑
这里的两个建议似乎是两个非常不同但同样好的重构:
为了便于阅读:
def predicted_deaths(population_density, population, state)
factor = case population_density
when 0...50 then 0.05
when 50...100 then 0.1
when 100...150 then 0.2
when 150...200 then 0.3
else 0.4
end
number_of_deaths = (population * factor).floor
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
更简洁但可读性更差:
def predicted_deaths(population_density, population, state)
number_of_deaths = (population * 0.05).floor
for i in 1..4
number_of_deaths = (0.1 * i * population).floor if population_density.between?(50*i, 50*(i+1)) || population_density >= 200
end
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
考虑这个未经测试的代码:
def predicted_deaths(population_density, population, state)
pct = case
when population_density >= 200
0.4
when population_density >= 150
0.3
when population_density >= 100
0.2
when population_density >= 50
0.1
else
0.05
end
ap "#{state} will lose #{ (population * pct).floor } people in this outbreak"
end
我经历了几个步骤来重构这样的代码,首先是寻找重复的部分并尝试将它们移动到条件测试的 down/out(本中的 case
语句)。 .. 呃...案例)。
这是第一遍:
def predicted_deaths(population_density, population, state)
number_of_deaths = case
when @population_density >= 200
(@population * 0.4).floor
when @population_density >= 150
(@population * 0.3).floor
when @population_density >= 100
(@population * 0.2).floor
when @population_density >= 50
(@population * 0.1).floor
else
(@population * 0.05).floor
end
ap "#{@state} will lose #{number_of_deaths} people in this outbreak"
end
此时很明显 @population *
和 floor
是多余的,所以我把它们移了下来。
虽然您使用实例变量和局部变量存在问题。您引用 @population_density
、@population
和 @state
,但方法参数中有局部变量,这些变量用于传递值。你不能那样做。删除 @
将变量变成局部变量。
def predicted_death(population_density, population, state)
number_of_death = (@population * 0.05).floor
for i in 1..4
number_of_death = (0.1 * i * @population).floor if @population_density.between?(50*i, 50*(i+1)) || @population_density >= 200
end
ap "#{@state} will lose #{number_of_deaths} people in this outbreak"
end
几件事:
1) 您可以使 case 语句使用单个赋值:
state = case(city)
when "Miami" then "Florida"
when "Omaha" then "Nebraska"
...
end
2) 你可以创建一个包含不常见逻辑的辅助函数(这将有助于显示什么不是 DRY):
def percentage_of_deaths_for_population_density(population_density)
case
when population_density >= 200 then 0.4
when population_density >= 150 then 0.3
when population_density >= 100 then 0.2
when population_density >= 50 then 0.1
else 0.05
end
然后您可以将代码段重写为:
def predicted_deaths(population_density, population, state)
number_of_deaths = (population * percentage_of_deaths_for_population_density(population_density)).floor
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
3) 最后,如果你关心,你可以进一步重构 percentage_of_deaths_for_population
(但我认为它的可读性很好,可能会保留它——如果你有一个巨大的声明,这真的只是):
def percentage_of_deaths_for_population(population)
{ 200 => 0.4, 150 => 0.3, 100 => 0.2, 50 => 0.1 }.each do |limit, ratio|
return ratio if population >= limit
end
return 0.05
end
4) 如果传入相同的变量,请不要使用实例变量!很混乱。
一种方法是缩短案例陈述:
def predicted_deaths(population_density, population, state)
factor = case population_density
when 0...50 then 0.05
when 50...100 then 0.1
when 100...150 then 0.2
when 150...200 then 0.3
else 0.4
end
number_of_deaths = (population * factor).floor
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
你可以用油煮我,但我会使用散列而不是 case
语句。
FACTORS_BY_DENSITY = { 200=>0.4, 150=>0.3, 100=>0.2, 50=>0.1, 0=>0.05 }
@data_by_state = {..., "Utah"=>{pop: 4_325_641, pop_density: 126 },...}
def predicted_deaths(state)
state_data = @data_by_state[state]
(state_data[:pop] * factor(state_data[:pop_density])).to_i
end
def factor(density)
FACTORS_BY_DENSITY.find { |d,_| density >= d }.pop
end
state = "Utah"
deaths = predicted_deaths(state)
#=> 865128
puts "#{state} will lose #{deaths} people in this outbreak"
# Utah will lose 865128 people in this outbreak
我经常发现自己的 if/else 语句在与不同的值进行比较时基本上重复了同一行。在这里,我正在编写代码来预测致命流感爆发造成的死亡人数。它已被重构为一个 case 语句,仍然很 WET:
def predicted_deaths(population_density, population, state)
case
when population_density >= 200 then number_of_deaths = (population * 0.4).floor
when population_density >= 150 then number_of_deaths = (population * 0.3).floor
when population_density >= 100 then number_of_deaths = (population * 0.2).floor
when population_density >= 50 then number_of_deaths = (population * 0.1).floor
else number_of_deaths = (population * 0.05).floor
end
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
我试着找一些东西和
一起工作j = 0.4
i = 200
until i <= 50 do
@population_density >= i then number_of_deaths = (@population * j).floor
i -= 50
j -= 0.1
end
但这并没有真正做同样的事情。
如何使重复的 case 语句更干?
编辑
这里的两个建议似乎是两个非常不同但同样好的重构:
为了便于阅读:
def predicted_deaths(population_density, population, state)
factor = case population_density
when 0...50 then 0.05
when 50...100 then 0.1
when 100...150 then 0.2
when 150...200 then 0.3
else 0.4
end
number_of_deaths = (population * factor).floor
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
更简洁但可读性更差:
def predicted_deaths(population_density, population, state)
number_of_deaths = (population * 0.05).floor
for i in 1..4
number_of_deaths = (0.1 * i * population).floor if population_density.between?(50*i, 50*(i+1)) || population_density >= 200
end
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
考虑这个未经测试的代码:
def predicted_deaths(population_density, population, state)
pct = case
when population_density >= 200
0.4
when population_density >= 150
0.3
when population_density >= 100
0.2
when population_density >= 50
0.1
else
0.05
end
ap "#{state} will lose #{ (population * pct).floor } people in this outbreak"
end
我经历了几个步骤来重构这样的代码,首先是寻找重复的部分并尝试将它们移动到条件测试的 down/out(本中的 case
语句)。 .. 呃...案例)。
这是第一遍:
def predicted_deaths(population_density, population, state)
number_of_deaths = case
when @population_density >= 200
(@population * 0.4).floor
when @population_density >= 150
(@population * 0.3).floor
when @population_density >= 100
(@population * 0.2).floor
when @population_density >= 50
(@population * 0.1).floor
else
(@population * 0.05).floor
end
ap "#{@state} will lose #{number_of_deaths} people in this outbreak"
end
此时很明显 @population *
和 floor
是多余的,所以我把它们移了下来。
虽然您使用实例变量和局部变量存在问题。您引用 @population_density
、@population
和 @state
,但方法参数中有局部变量,这些变量用于传递值。你不能那样做。删除 @
将变量变成局部变量。
def predicted_death(population_density, population, state)
number_of_death = (@population * 0.05).floor
for i in 1..4
number_of_death = (0.1 * i * @population).floor if @population_density.between?(50*i, 50*(i+1)) || @population_density >= 200
end
ap "#{@state} will lose #{number_of_deaths} people in this outbreak"
end
几件事:
1) 您可以使 case 语句使用单个赋值:
state = case(city)
when "Miami" then "Florida"
when "Omaha" then "Nebraska"
...
end
2) 你可以创建一个包含不常见逻辑的辅助函数(这将有助于显示什么不是 DRY):
def percentage_of_deaths_for_population_density(population_density)
case
when population_density >= 200 then 0.4
when population_density >= 150 then 0.3
when population_density >= 100 then 0.2
when population_density >= 50 then 0.1
else 0.05
end
然后您可以将代码段重写为:
def predicted_deaths(population_density, population, state)
number_of_deaths = (population * percentage_of_deaths_for_population_density(population_density)).floor
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
3) 最后,如果你关心,你可以进一步重构 percentage_of_deaths_for_population
(但我认为它的可读性很好,可能会保留它——如果你有一个巨大的声明,这真的只是):
def percentage_of_deaths_for_population(population)
{ 200 => 0.4, 150 => 0.3, 100 => 0.2, 50 => 0.1 }.each do |limit, ratio|
return ratio if population >= limit
end
return 0.05
end
4) 如果传入相同的变量,请不要使用实例变量!很混乱。
一种方法是缩短案例陈述:
def predicted_deaths(population_density, population, state)
factor = case population_density
when 0...50 then 0.05
when 50...100 then 0.1
when 100...150 then 0.2
when 150...200 then 0.3
else 0.4
end
number_of_deaths = (population * factor).floor
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
你可以用油煮我,但我会使用散列而不是 case
语句。
FACTORS_BY_DENSITY = { 200=>0.4, 150=>0.3, 100=>0.2, 50=>0.1, 0=>0.05 }
@data_by_state = {..., "Utah"=>{pop: 4_325_641, pop_density: 126 },...}
def predicted_deaths(state)
state_data = @data_by_state[state]
(state_data[:pop] * factor(state_data[:pop_density])).to_i
end
def factor(density)
FACTORS_BY_DENSITY.find { |d,_| density >= d }.pop
end
state = "Utah"
deaths = predicted_deaths(state)
#=> 865128
puts "#{state} will lose #{deaths} people in this outbreak"
# Utah will lose 865128 people in this outbreak