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/systemsandse... 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.

on 2007-04-18 19:15

on 2007-04-18 19:24

On Apr 18, 2007, at 1:15 PM, Tim Chater 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 Stewart Play: http://james.anthropiccollective.org Work: http://jystewart.net/process/

on 2007-04-19 13:11

James Stewart 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...