用于插值动态变量参考的exter()替代方案



在以下代码中:

def solve(a0, a1, a2, b0, b1, b2)
    #score index:  0 = james, 1 = sam
    score = Array.new(2, 0)
    calcScore = lambda do |x,y| 
        if ( x > y )
            score[0] += 1
        end
        if ( x < y )
            score[1] += 1       
        end
    end
    0.upto 2 do |index|
        calcScore.call(eval("a#{index}"),eval("b#{index}"))
    end
    score
end

是否有一种更雄辩的干燥方法来实现动态变量参考,而无需使用:

eval("a#{index}")

local_variable_geteval似乎在这里工作,正确的方法是:

def solve(a0, a1, a2, b0, b1, b2)
  a, b = [a0, a1, a2], [b0, b1, b2]
  # deal with score
  0.upto 2 do |index|
    calcScore.call(a[index], b[index])
  end
  score
end

或更好,更干燥:

def solve(*as_and_bs)
  raise unless as_and_bs.size == 6
  a, b = as_and_bs(0..2), as_and_bs(3..5)
  # deal with score
  0.upto 2 do |index|
    calcScore.call(a[index], b[index])
  end
  score
end

使用 binding.local_variable_get

 0.upto 2 do |index|
   calcScore.call(binding.local_variable_get("a#{index}"),
                  binding.local_variable_get("b#{index}"))
 end

eval是邪恶的。不要使用它。这是一个等效的代码,该代码应适用于任何数量的分数。它使用a <=> b返回-101

的事实

您的输入格式不是很方便。该代码使用each_slice并转台将[1,2,3,4,5,6]转换为[[1, 4], [2, 5], [3, 6]]。然后,您可以迭代游戏以计算总分:

def calc_score(a, b)
  [[0, 0], [1, 0], [0, 1]][a <=> b]
end
def solve(*scores)
  size = scores.size
  raise 'Need an even number of scores' unless size.even?
  raise 'Need at least two scores' unless size > 0
  scores.each_slice(size / 2).to_a.transpose.inject([0, 0]) do |(a_total, b_total), (a, b)|
    a_score, b_score = calc_score(a, b)
    [a_total + a_score, b_total + b_score]
  end
end

甚至较短:

def solve(*scores)
  size = scores.size
  raise 'Need an even number of scores' unless size.even?
  raise 'Need at least two scores' unless size > 0
  scores.each_slice(size / 2).to_a.transpose.map do |a, b|
    calc_score(a, b)
  end.transpose.map{ |s| s.inject(:+) } # .map(&:sum) in Ruby 2.4
end

作为一个例子:

solve(1, 2, 3, 4, 5, 6)
# [0, 3]
solve(2, 0, 0, 3)
# [1, 1]

如果将A1,A2和A3组合到数组中并使用B进行相同的操作,则可以使用常规[]索引:

def solve(a, b)
    #score index:  0 = james, 1 = sam
    score = Array.new(2, 0)
    calcScore = lambda do |x,y| 
        if ( x > y )
            score[0] += 1
        end
        if ( x < y )
            score[1] += 1       
        end
    end
    0.upto 2 do |index|
        calsScore.call(a[index], b[index])
    end
    score
end

您还可以添加自定义错误检查数组长度:

raise(ArgumentError) unless [a,b].all? { |arr| arr.length == 3 }

最新更新