0

我有一个 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 = ">"- 然后使用该变量将运算符替换为代码块或其他东西?有任何想法吗?

4

3 回答 3

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
于 2013-01-24T20:56:52.340 回答
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
于 2013-01-24T21:00:03.610 回答
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! 并且可能会产生更好的性能
于 2013-01-24T21:52:11.947 回答