【问题标题】:Ruby: Refactoring a complicated nested-loop methodRuby:重构复杂的嵌套循环方法
【发布时间】:2012-01-14 23:18:31
【问题描述】:

我正在尝试消除我的代码中的重复。我有一个用跳棋填充棋盘的方法:

def populate_checkers
  evens = [0, 2, 4, 6]
  odds  = [1, 3, 5, 7]

  0.upto(2) do |x_coord|
    if x_coord.even?
      evens.each do |y_coord|
        red_checker = Checker.new(x_coord, y_coord, :red)
        @board[x_coord][y_coord] = red_checker 
      end
    elsif x_coord.odd?
      odds.each do |y_coord|
        red_checker = Checker.new(x_coord, y_coord, :red)
        @board[x_coord][y_coord] = red_checker 
      end
    end
  end

  5.upto(7) do |x_coord|
    if x_coord.even?
      evens.each do |y_coord|
        black_checker = Checker.new(x_coord, y_coord, :black)
        @board[x_coord][y_coord] = black_checker 
      end
    elsif x_coord.odd?
      odds.each do |y_coord|
        black_checker = Checker.new(x_coord, y_coord, :black)
        @board[x_coord][y_coord] = black_checker 
      end
    end
  end
end

如何删除重复并仍然获得我需要的精确行为?

【问题讨论】:

  • 旁注:从函数式编程的角度来看,这种代码非常非常糟糕。您调用一个方法并“神奇地”填充了一些实例变量(@board),唉,参考透明度正在走下坡路。更好地编写获取参数并返回某些内容的方法:@board = build_board。更多关于 Ruby 的 FP:slideshare.net/tokland/functional-programming-with-ruby-9975242

标签: ruby refactoring iteration


【解决方案1】:
def populate_checkers
  evens = [0, 2, 4, 6]
  odds  = [1, 3, 5, 7]

  [0.upto(2), 5.upto(7)].each_with_index do |enum, i|
    enum.each do |x_coord|
      (x_coord.even? ? evens : odds).each do |y_coord|
        checker = Checker.new(x_coord, y_coord, i == 0 ? :red : :black)
        @board[x_coord][y_coord] = checker 
      end
    end
  end
end

可能有更好的方法来进行计数,但这就是我得到的。

这里有一个可能更好的解决方案...

def populate_checkers
  { :red => (0..2), :black => (5..7) }.each do |color, range|
    range.each do |x_coord|
      (x_coord.even? ? 0 : 1).step(7, 2) do |y_coord|
        checker = Checker.new(x_coord, y_coord, color)
        @board[x_coord][y_coord] = checker 
      end
    end
  end
end

【讨论】:

    【解决方案2】:
    0.upto(2) do |x|
      0.upto(7) do |y|
        @board[x][y]=Checker.new(x, y, :red) if (x+y).even? 
      end
    end
    

    这仅适用于红军。

    【讨论】:

      【解决方案3】:

      您可以尝试提取方法,然后将块提取到 lambda 中。然后你的代码将是可读的并且没有重复

      def populate_checkers
        0.upto(2) do |x_coord|
          populate_checker(x_coord, :red)
        end
      
        5.upto(7) do |x_coord|
          populate_checker(x_cord, :black)
        end
      end
      
      def populate_checker(x_coord, color)
        evens = [0, 2, 4, 6]
        odds  = [1, 3, 5, 7]
      
        apply_checker = lambda do |y_coord|
         checker = Checker.new(x_coord, y_coord, color)
         @board[x_coord][y_coord] = checker
        end
      
        if x_coord.even?
          evens.each(&apply_checker)
        elsif x_coord.odd?
          odds.each(&apply_checker)
        end
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-26
        • 1970-01-01
        • 1970-01-01
        • 2013-01-17
        • 2018-05-09
        • 2017-11-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多