1

RubyでFedEx追跡番号のチェックディジット計算を作成しようとしています。

チェックディジット計算の情報と手順は次のとおりです。

  • 数字の位置は右から左にラベル付けされています。
  • 数字1はチェック文字です。
  • 16から22の数字は使用されません。

手順:

  1. 位置2から始めて、偶数の位置の値を合計します
  2. ステップ1の結果に3を掛けます。
  3. 位置3から始めて、奇数の位置の値を合計します。覚えておいてください–位置1は、計算しようとしているチェックディジットです。
  4. 手順2の結果を手順3の結果に追加します。
  5. 手順4の数値に加算すると、10の倍数になる最小の数値を決定します。これがチェックディジットです。

プロセスの例を次に示します(FedExが提供)。 ここに画像の説明を入力してください

では、これをRubyで実装するにはどうすればよいですか?

4

2 に答える 2

6

あなたが文字列としてあなたの数を持っているとき(またはあなたがあなたの数字を整数として持っているなら、#to_sそれだけで文字列を取得する)、そしてあなたはそこから簡単に数字を抽出することができます:

number_string[idx].to_i

またはRuby1.8を使用している場合

number_string[idx..idx].to_i

#to_iそれを整数に変換するので、他の人に追加することができます。次に、提供された手順に進んで番号を計算します。

idxそれを実装するためにあなたがしなければならないのは、数値の文字列表現のインデックス位置に命令で提供された位置を正しくマップすることです。頭を数えて紙の上でそれを行うか、Rubyで負のidx(文字列の終わりから数える)を使用してください。

編集

解決策は次のようになります。

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つの文字列を長さ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はタプルであり、[digit、pos]のペアです。
  • 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

誰かがそれを求めない限り、それは説明する価値のない、完全に単純な解決策です

于 2011-08-29T13:02:26.383 に答える