Checking validity of NHS numbers


#1

Hello

I need to check that the NHS numbers in my database are valid. I’m
storing them as ten-digit strings: the first nine are the identifier and
the tenth is a check digit.

There are four steps to calculating the check digit (from
http://www.connectingforhealth.nhs.uk/systemsandservices/nsts/docs/tech_nn_check_digit.pdf):

  1. multiply each of the first nine digits by a weighting factor (10 for
    the first digit, 9 for the second… 2 for the ninth)

  2. sum the results of these multiplications

  3. divide the total by 11 and establish the remainder

  4. subtract the remainder from 11 to give the check digit.

If the result of step 4 is 11 a check digit of 0 is used; if the result
is 10 then the number is invalid.

I’m struggling to implement this into my model. I imagine that the first
thing is to convert the string to an array:

nhs_no = “1234567890”
nhs_no.split("").map{ |v| v.to_i } # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]

Then I get a bit stuck (i.e. before step 1!): I want to transform the
first nine digits of the array so that the new value of the kth element
is v*(10-k).

I hope this makes some sense, and I’d really appreciate any help.

Thanks.


#2

On Apr 18, 2007, at 1:15 PM, Tim C. wrote:

tech_nn_check_digit.pdf):

9, 0]

Then I get a bit stuck (i.e. before step 1!): I want to transform the
first nine digits of the array so that the new value of the kth
element
is v*(10-k).

You probably want the Enumerable#each_with_index method, eg.

new_array = []
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0].each_with_index do |value, index|
new_array.push(value * (10 - index))
end

James.


James S.
Play: http://james.anthropiccollective.org
Work: http://jystewart.net/process/


#3

James S. wrote:

You probably want the Enumerable#each_with_index method, eg.

new_array = []
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0].each_with_index do |value, index|
new_array.push(value * (10 - index))
end

Thank you James! In case anyone’s interested here’s a function which
returns the check digit for a given NHS number string:

def check_digit(nhs_number)
# must be ten digits long
unless nhs_number.length == 10
check_digit = nil
else
new_array = []
nhs_number.split("").map{ |v| v.to_i }.each_with_index do |value,
index|
new_array.push(value * (10 - index)) if index < 9
end
check_digit = 11-new_array.sum.remainder(11)
# recode check digit of 11 to 0 and ‘disallow’ 10
case check_digit
when 11 then check_digit = 0
when 10 then check_digit = nil
end
# disallow NHS numbers like “1111111111”, “2222222222” etc.
check_digit = nil if check_digit.to_s*10 == nhs_number
end
check_digit
end

I’m sure that I could make this more elegant somehow, especially if
there were a ‘map_with_index’ function…