Task

For each number list of 6-digit SEDOLs, calculate and append the checksum digit.



That is, given this input:

710889
B0YBKJ
406566
B0YBLH
228276
B0YBKL
557910
B0YBKR
585284
B0YBKT
B00030

Produce this output:

7108899
B0YBKJ7
4065663
B0YBLH2
2282765
B0YBKL9
5579107
B0YBKR5
5852842
B0YBKT7
B000300

Extra credit

Check each input is correctly formed, especially with respect to valid characters allowed in a SEDOL string.



Related tasks

   Luhn test
   ISIN


defmodule SEDOL do
  @sedol_char  "0123456789BCDFGHJKLMNPQRSTVWXYZ" |> String.codepoints
  @sedolweight  [1,3,1,7,3,9]
 
  defp char2value(c) do
    unless c in @sedol_char, do: raise ArgumentError, "No vowels"
    String.to_integer(c,36)
  end
 
  def checksum(sedol) do
    if String.length(sedol) != length(@sedolweight), do: raise ArgumentError, "Invalid length"
    sum = Enum.zip(String.codepoints(sedol), @sedolweight)
          |> Enum.map(fn {ch, weight} -> char2value(ch) * weight end)
          |> Enum.sum
    to_string(rem(10 - rem(sum, 10), 10))
  end
end
 
data = ~w{
          710889
          B0YBKJ
          406566
          B0YBLH
          228276
          B0YBKL
          557910
          B0YBKR
          585284
          B0YBKT
          B00030
          C0000
          1234567
          00000A
         }
 
Enum.each(data, fn sedol ->
  :io.fwrite "~-8s ", [sedol]
  try do
    IO.puts sedol <> SEDOL.checksum(sedol)
  rescue
    e in ArgumentError -> IO.inspect e
  end
end)