Forum: Ruby on Rails Checking validity of NHS numbers

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Tim C. (Guest)
on 2007-04-18 21:15
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.
James S. (Guest)
on 2007-04-18 21:24
(Received via mailing list)
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/
Tim C. (Guest)
on 2007-04-19 15:11
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...
This topic is locked and can not be replied to.