Help me refactor implementing Luhn algorithm, which is described as follows:
The formula verifies a number against its included check digit, which is usually appended to a partial account number to generate the full account number. This account number must pass the following test:
- From the rightmost digit, which is the check digit, moving left, double the value of every second digit; if the product of this doubling operation is greater than 9 (e.g., 8 × 2 = 16), then sum the digits of the products (e.g., 16: 1 + 6 = 7, 18: 1 + 8 = 9).
- Take the sum of all the digits.
- If the total modulo 10 is equal to 0 (if the total ends in zero) then the number is valid according to the Luhn formula; else it is not valid.
Assume an example of an account number "7992739871" that will have a check digit added, making it of the form 7992739871x:
Account number 7 9 9 2 7 3 9 8 7 1 xDouble every other 7 18 9 4 7 6 9 16 7 2 -Sum of digits 7 9 9 4 7 6 9 7 7 2 =67The check digit (x) is obtained by computing the sum of digits then computing 9 times that value modulo 10 (in equation form, (67 × 9 mod 10)). In algorithm form:
- Compute the sum of the digits (67).
- Multiply by 9 (603).
- The last digit, 3, is the check digit. Thus, x=3.
Following is my implementation, it works but could be a lot better, I believe.
def credit_check(num)
verify = num.to_s.split('').map(&:to_i)
half1 = verify.reverse.select.each_with_index { |str, i| i.even? }
half1 = half1.inject(0) { |r,i| r + i }
# This implements rule 1
half2 = verify.reverse.select.each_with_index { |str, i| i.odd? }
double = half2.map { |n| n * 2 }
double = double.map { |n| n.to_s.split('') }
double = double.flatten.map(&:to_i)
double = double.inject(0) { |r,i| r + i }
final = double + half1
puts final % 10 == 0 && (num.to_s.length > 12 && num.to_s.length < 17) ? "VALID" : "INVALID"
end
I'm a rank noob at all of this, obviously. But I appreciate any help, including proper style!