Ruby中的Luhn算法

时间:2013-08-09 01:37:28

标签: ruby algorithm luhn

我一直在尝试在Ruby中实现Luhn算法,但不断收到错误消息,即nil无法核心到Fixnum中。

Luhn算法应该:

从倒数第二位开始,每隔一位数加倍,直到达到第一位数

求和所有未触及的数字和加倍的数字(需要将双位数分开,10变为1 + 0)

如果总数是10的倍数,则表示您已收到有效的信用卡号码!

这就是我所拥有的:

class CreditCard
  def initialize (card_number)
    if (card_number.to_s.length != 16 )
        raise ArgumentError.new("Please enter a card number with exactly 16 integars")
    end
    @card_number = card_number
    @total_sum = 0
  end

  def check_card
    @new_Array = []
    @new_Array = @card_number.to_s.split('')
    @new_Array.map! { |x| x.to_i }
    @new_Array.each_with_index.map { |x,y| 
      if (y % 2 != 0) 
        x = x*2
      end  
     }  
    @new_Array.map! {|x| 
     if (x > 9)
        x = x-9 
      end  
    }
    @new_Array.each { |x| 
        @total_sum = @total_sum + x
    }  
    if (@total_sum % 10 == 0)
      return true
    else
      return false      
    end  
  end  
end

3 个答案:

答案 0 :(得分:2)

在你的

部分
@new_Array.each_with_index.map { |x,y| 
  if (y % 2 != 0) 
    x = x*2
  end  
}

这些变化不是永久性的。另外,正如Victor所写,如果测试失败,你的@new_Array将被填充为nils。最后

if (@total_sum % 10 == 0)
  return true
else
  return false      
end

你可以简单地写

@total_sum % 10 == 0

因为ruby方法中的最后一行已经是返回。我找到了slightly different algorithm并在此处实施了它:

# 1) Reverse the order of the digits in the number.
# 2) Take the first, third, ... and every other odd digit in the reversed digits
#   and sum them to form the partial sum s1
# 3) Taking the second, fourth ... and every other even digit in the reversed digits:
#   a) Multiply each digit by two (and sum the digits if the answer is greater than nine) to form partial sums for the even digits
#   b) Sum the partial sums of the even digits to form s2
# 4) If s1 + s2 ends in zero then the original number is in the form of a valid credit card number as verified by the Luhn test.

def luhn n
  s = n.to_s.reverse
  sum=0
  tmp=0
  (0..s.size-1).step(2) {|k|    #k is odd, k+1 is even
    sum+=s[k].to_i   #s1
    tmp = s[k+1].to_i*2
    tmp = tmp.to_s.split(//).map(&:to_i).reduce(:+) if tmp>9
    sum+=tmp
  }
  sum%10 == 0
end

[49927398716, 49927398717, 1234567812345678, 1234567812345670].each {|num|
  puts "%20s %s" % [num, luhn(num)]
}

#         49927398716 true
#         49927398717 false
#    1234567812345678 false
#    1234567812345670 true

希望这有帮助。

答案 1 :(得分:1)

if (x > 9)
  x = x-9
end

=>

x > 9 ? x - 9 : x

或者你也可以写

if x > 9
  x - 9
else
  x
end

如果没有else子句,if false; ...; end的值将始终为nil

答案 2 :(得分:0)

如果您不介意更改代码......

...
def check_card
  sum = 0
  @card_number.to_s.split("").each_with_index do |digit, index|
    d = digit.to_i
    sum += index % 2 == 1 ? d : d * 2 > 9 ? ( d * 2 - 9) : d * 2 
  end
  sum % 10 == 0
end

这只是立即获得数字的总和,如果索引是偶数(从第二个到最后一个开始的每隔一个数字是一个偶数,从数组索引的角度来看)将它加倍并减去9.然后模数10到底是什么