Как вычисляется контрольная цифра в Ruby?

Я пытаюсь построить расчет контрольных цифр в Ruby для номеров отслеживания FedEx.

Вот информация и шаги для вычисления контрольной цифры:

  • Цифровые позиции обозначены справа налево.
  • Цифра 1 - символ проверки.
  • Цифры с 16 по 22 не используются.

шаги:

  1. Начиная с позиции 2, сложите значения четных позиций.
  2. Умножьте результаты шага один на три.
  3. Начиная с позиции 3, сложите значения нечетных позиций. Помните - позиция 1 - это контрольная цифра, которую вы пытаетесь вычислить.
  4. Добавьте результат второго шага к результату третьего шага.
  5. Определите наименьшее число, которое при добавлении к номеру из шага четыре дает кратное 10. Это контрольная цифра.

Вот пример процесса (предоставлен FedEx):

Итак, как мне реализовать это в Ruby?

2 ответа

Решение

Когда у вас есть номер в виде строки (или если у вас есть цифра в виде целого числа, просто #to_s на нем и получите строку), а затем вы можете просто извлечь цифры оттуда с помощью:

number_string[idx].to_i

или если вы используете Ruby 1.8

number_string[idx..idx].to_i

#to_i это преобразовать его в целое число, чтобы вы могли добавить его к другим. Затем просто перейдите к шагам, указанным для расчета вашего числа.

Все, что вам нужно сделать для его реализации, это правильно отобразить положения, указанные в инструкции к idx позиция индекса в вашем строковом представлении числа. Просто сделайте это на бумаге с подсчетом в голове или используйте отрицательный idx (он считается с конца строки) в Ruby.

РЕДАКТИРОВАТЬ:

Решение может быть что-то вроде этого:

bar_code_data = "961102098765431234567C"
digits_with_position = bar_code_data.reverse[1..14].split(//).map(&:to_i).zip(2..1/0.0)

это идет следующим образом:

  • reverse - обратная строка, так что теперь мы можем считать слева направо вместо обратного
  • [1..14] - выберите подстроку символов, которые нас интересуют (Ruby считает от 0)
  • split(//) - разбить одну строку на подстроки длиной 1 символ, другими словами - отдельные цифры
  • map(&:to_i) - вызвать #to_i для каждого элемента массива, другими словами преобразовать в целое число
  • zip(2..1/0.0) - добавить позицию, начиная с 2 до бесконечности, для каждого элемента

Теперь у нас должно быть что-то вроде этого:

[[7, 2], [6, 3], [5, 4], [4, 5], [3, 6], [2, 7], [1, 8], [3, 9], [ 4, 10], [5, 11], [6, 12], [7, 13], [8, 14], [9, 15]]

sum = digits_with_position.map{|i| i[0] * (i[1].even? ? 3 : 1)}.reduce(+:)

Мы внесли небольшие изменения в алгоритм, которому не должно быть сложно следовать:

вместо:

sum = (in[2] + in[4] + in[6] + ...)*3 + (in[3] + in[5] + in[7] + ...)

мы сделали:

sum = in[2]*3 + in[3]*1 + in[4]*3 + in[5]*1 + in[6]*3 + in[7]*1 + ...

что является тем же результатом, но с измененным порядком операций.

Также:

  • map {|i| ... } - отобразить каждое значение списка, в нашем случае это кортеж, пара [цифра, позиция]
  • i[1].even? - проверить, является ли позиция четной
  • i[1].even? ? 3 : 1 - для четного положения используйте 3, для противоположного (нечетного) используйте только 1
  • reduce(:+) - уменьшить результирующий массив до единого значения с помощью операции + (добавить все результаты)

Теперь самое интересное:-)

check_code = 10 - (sum % 10)
  • sum % 10 - модуль 10 суммы сумм, возвращающий напоминание о сумме деления на 10, которая в нашем случае является последней цифрой
  • 10 - (sum % 10) - дополнить до ближайшего, не меньшего, кратного 10

В описании есть ошибка, потому что если в результате вы получите 130, то следующее большее кратное 10 будет 140, а разница равна 10, что не является правильным результатом для цифры (вероятно, она должна быть 0).

Другое более быстрое решение было бы следующим (разверните все циклы, просто жестко закодируйте все):

d = "961102098765431234567C".split(//) # avoid having to use [-2..-2] in Ruby 1.8
sum_even = d[-2].to_i + d[-4].to_i + d[-6].to_i + d[-8].to_i + d[-10].to_i + d[-12].to_i + d[-14].to_i
sum_odd = d[-3].to_i + d[-5].to_i + d[-7].to_i + d[-9].to_i + d[-11].to_i + d[-13].to_i + d[-15].to_i
sum = sum_even * 3 + sum_odd
check_code = 10 - sum % 10

Это просто мёртвое простое решение, объяснять не стоит, если только кто-то не попросит его

Передайте свой номер указанному ниже методу, и он вернет число, к которому добавлена ​​цифра контрольной суммы. Ссылка использована с: https://www.gs1.org/services/how-calculate-check-digit-manually

      def add_check_digit(code_value) 
   sum = 0
   code_value.to_s.split(//).each_with_index{|i,index| sum = sum + (i[0].to_i * ((index+1).even? ? 3 : 1))}
   check_digit = sum.zero? ? 0 : (10-(sum % 10))
   return (code_value.to_s.split(//)<<check_digit).join("")
end
Другие вопросы по тегам