Calculate a Check Digit of JAN in Ruby One Liner

タイトルめっちゃかっこつけたけども.最近このブログでプログラミングの話してなかったんで久しぶりに.

そういえばバーコードの最後って誤り確認用の符号なんだよな,それぐらいのプログラムだったら自分でも書けそうだな,と思ってから一体何ヶ月が経ったのか.ようやく手を動かしました.

まずは普通に書いたものから.

jancode = gets.chomp
sum = 0
 
jancode.reverse.each_char.with_index do |e, i|
  i.even? ? sum += e.to_i * 3 : sum += e.to_i
end
 
print "Check Digit is: ", (10 - sum.to_s[-1].to_i).to_s[-1], "\n"

JANコードについて調べてみるとどうやらいろんな桁数のものがあるとのことだったので,普通にひっくり返して偶数桁と奇数桁で場合分けすることに.しかも 10 から引く数が 0 だったときにチェックディジットも 10 になってしまうので,余計なことは考えずに「計算結果の下 1 桁」にしておきました.

で.ここまでなら誰でも書けるんですよ.たぶん.これをどうやって一行にまとめるかが勘違いプログラマーの腕の見せどころなわけで.見せる腕無いけど.

puts (10 - gets.chomp.reverse.split("").map(&:to_i).each_with_object([]).with_index{|(e, arr), i| i.even? ? arr << e * 3 : arr << e}.inject(:+).to_s[-1].to_i).to_s[-1]

で,出来たのがこれと.

標準入力から読み込み→改行文字取り除き→ 1 文字ごとに分割し→各要素を文字列から数字にし→それぞれの要素について→添字もつけて→偶数桁なら 3 倍して,奇数桁ならそのまま新しい配列にプッシュしていく→その配列の総和を取る→その数の 1 桁目を 10 から引いた数の下 1 桁がチェックディジット

という流れでした.

each_with_object の部分はいろいろ迷走しました.each を使うと外に変数を用意しておかなきゃいけなかったりとか.inject でもよさそうだけど,書いてた時はいつものように変数のスコープだとかにハマってたんで,リファレンスに書いてあった each_with_object を使うことに.さらに桁数も判断したいので後ろに with_index もくっつけて.この後のブロック変数は,もともと each_with_object の引数だった部分を括弧でくくらないとエラーになってました.なってた気がします.たぶん with_index から見て必ず引数が 2 個じゃないといけないのかなーというのが個人的な曖昧予想なのですが.中がどうなっているのかが分からないので知りません(小並感).each_with_object の引数を外で定義した変数 sum = 0 にしたら返り値が毎回 0 になったのでそれも気になるところですが.あと最近すごい H 本を読んでたので,to_i とか to_s とか書きながら「動的型付けって怖いな」と思いました(小並感).あとこの 1 行が完成するのに 45 分ぐらいかかったので本当に鈍ってるなと思いました(小並感).冬休みが終わったらまたプログラミングの授業の続きがあるので気を付けたいところです.

コメント

このブログの人気の投稿

慶大プレ小論文

改名