我有一个跟踪号码上的校验位的方法,但它只是感觉冗长/草率。它可以被重构并且通常被清理干净吗?
我正在运行Ruby 1.8.7。
def is_fedex(number)
n = number.reverse[0..14]
check_digit = n.first.to_i
even_numbers = n[1..1].to_i + n[3..3].to_i + n[5..5].to_i + n[7..7].to_i + n[9..9].to_i + n[11..11].to_i + n[13..13].to_i
even_numbers = even_numbers * 3
odd_numbers = n[2..2].to_i + n[4..4].to_i + n[6..6].to_i + n[8..8].to_i + n[10..10].to_i + n[12..12].to_i + n[14..14].to_i
total = even_numbers + odd_numbers
multiple_of_ten = total + 10 - (total % 10)
remainder = multiple_of_ten - total
if remainder == check_digit
true
else
false
end
end
编辑:以下是有效和无效的数字。
有效身份:9612019950078574025848
无效:9612019950078574025847
答案 0 :(得分:2)
def is_fedex(number)
total = (7..20).inject(0) {|sum, i| sum + number[i..i].to_i * ( i.odd? ? 1 : 3 ) }
number[-1].to_i == (total / 10.0).ceil * 10 - total
end
我相信你应该保留你的代码。虽然它不是惯用的或聪明的,但是从现在开始几个月你就会很难理解它。
答案 1 :(得分:1)
我不是一个红宝石程序员,所以如果任何语法都没有,我道歉但你应该得到一般的想法。我看到的一些事情:首先,您不需要对数组进行切片,单个索引就足够了。第二,你可以做类似的事情,而不是分裂甚至是奇数:
total = 0
for i in (1..14)
total += n[i].to_i * ( i % 2 == 1 ? 1 : 3 )
end
第三,余数可以简化为10 - (总%10)。
答案 2 :(得分:1)
我意识到你正在运行1.8.7,但这是我尝试使用each_slice并同时注入一个1.9.2功能:
def is_fedex(number)
total = number.reverse[1..14].split(//).map(&:to_i).each_slice(2).inject(0) do |t, (e,o)|
t += e*3 + o
end
10 - (total % 10) == number[-1].to_i
end
它通过了两个测试
答案 3 :(得分:0)
尝试一下:
#assuming number comes in as a string
def is_fedex(number)
n = number.reverse[0..14].scan(/./)
check_digit = n[0].to_i
total = 0
n[1..14].each_with_index {|d,i| total += d.to_i * (i.even? ? 3 : 1) }
check_digit == 10 - (total % 10)
end
> is_fedex("12345678901231") => true
编辑合并了简化的余数逻辑,如Kevin建议的那样
答案 4 :(得分:0)
这样的东西?
def is_fedex(number)
even_arr, odd_arr = number.to_s[1..13].split(//).map(&:to_i).partition.with_index { |n, i| i.even? }
total = even_arr.inject(:+) * 3 + odd_arr.inject(:+)
number.to_s.reverse[0..0].to_i == (total + 10 - (total % 10)) - total
end
如果你能给我一个有效且无效的号码,我可以测试它是否有效,并可能进一步调整它:)
答案 5 :(得分:0)
此功能应该:
def is_fedex(number)
# sanity check
return false unless number.length == 15
data = number[0..13].reverse
check_digit = number[14..14].to_i
total = (0..data.length-1).inject(0) do |total, i|
total += data[i..i].to_i * 3**((i+1)%2)
end
(10 - total % 10) == check_digit
end
算术表达式3**((i+1)%2)
可能看起来有点复杂,但与(i.odd? ? 1 : 3)
基本相同。两种变体都是正确的,你使用的是你自己(可能会影响速度......)
另请注意,如果您使用Ruby 1.9,则可以使用data[i]
而不是{1.8}所需的data[i..i]
。