有没有办法根据条件替换运营商?

时间:2013-01-24 20:49:24

标签: ruby

我有一个if / else条件,if和else部分是相同的,除了使用的运算符。在一个案例中<,在另一个案例>中。有没有办法有条件地设置该运算符,以干掉代码?

if count_year < end_year
    while count_year <= end_year
        if count_year % 4 == 0
            if count_year % 100 != 0
                all_years << count_year unless (count_year % 400 == 0)
            end
        end
        count_year += 1
    end
    puts all_years
elsif count_year > end_year
    while count_year >= end_year
        if count_year % 4 == 0
            if count_year % 100 != 0
                all_years << count_year unless (count_year % 400 == 0)
            end
        end
        count_year -= 1
    end
    puts all_years.reverse
end

这是在两年之间打印闰年的计划的一部分。我觉得必须有一种方法可以不必重复循环两次。类似于:count_year < end_year ? operator = "<" : operator = ">" - 然后使用该变量将运算符替换为代码块或其他内容?有什么想法吗?

3 个答案:

答案 0 :(得分:3)

对于一个小改进,您可以将完全相同的部分提取到方法中。然后重复停止如此庞大。

# I'm too lazy to come up with a proper name for it.
def foo count_year, all_years
  if count_year % 4 == 0
    if count_year % 100 != 0
      all_years << count_year unless (count_year % 400 == 0)
    end
  end
end


# later...

if count_year < end_year
  while count_year <= end_year
    foo count_year, all_years
    count_year += 1
  end
  puts all_years
elsif count_year > end_year
  while count_year >= end_year
    foo count_year, all_years
    count_year -= 1
  end
  puts all_years.reverse
end

但是,运营商替代......

是的,有一种方法可以动态选择运营商进行评估。你看,ruby中的运算符只是方法调用,仅此而已。这两行是等价的:

7 > 5
7.>(5)

这是一个选择随机运算符进行比较的片段。我把它留给你来适应你的问题(如果你愿意,那就是。我建议你不要这样做。)

def is_7_greater_than_5
  operator = [:<, :>].sample # pick random operator
  7.send(operator, 5)
end

is_7_greater_than_5 # => false
is_7_greater_than_5 # => false
is_7_greater_than_5 # => true
is_7_greater_than_5 # => true
is_7_greater_than_5 # => true

答案 1 :(得分:2)

def example count_year, end_year
  all_years = []

  dir, test = count_year < end_year                      ?
    [ 1, proc { |c, e| c <= e }] : count_year > end_year ?
    [-1, proc { |c, e| c >  e }] :
    [ 0, proc { |c, e| false  }]

  while test.call count_year, end_year
    if count_year % 4 == 0
      if count_year % 100 != 0
        all_years << count_year unless count_year % 400 == 0
      end
    end
    count_year += dir
    puts dir > 0 ? all_years : all_years.reverse
  end
end

答案 2 :(得分:0)

噢。你为什么要进行高尔夫练习并快速接受答案?嘘! :(嘿嘿。开个玩笑。早起的小鸟得了蠕虫。我也许太过字面意思了,因为我觉得你只是想试试比较。

我会使用ruby的内置函数并将此方法分解为一个类。 :)

require 'date'

class LeapYearFinder

  attr_reader :years, :years_reversed

  def initialize(start_year, end_year)
    @start_year    = Date.parse("1/1/#{start_year.to_s}")
    @end_year      = Date.parse("1/1/#{end_year.to_s}")
    @years         ||= leap_years
  end

  def compare_range
    @compare_range ||= Range.new(@start_year, @end_year)
  end

  def leap_years
    years = []
    compare_range.step {|x| years << x.year if x.leap? }
    years.uniq!
  end

  def years_reversed
    @years.reverse
  end

end

lp = LeapYearFinder.new(1900, 2012)

puts "Years putzed"
lp.years.map {|x| puts x}

puts "Years reversed"
lp.years_reversed.map {|x| puts x}

一些角落问题

  • 处理反向日期输入
  • 适当地穿过范围,从而避免 uniq!并可能产生更好的性能