在Clojure中计算GS1校验位的更多惯用方式 [英] More idiomatic way to calculate GS1 check digit in Clojure

查看:74
本文介绍了在Clojure中计算GS1校验位的更多惯用方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试计算 GS1校验位,并提出了以下建议码。用于计算校验位的算法为:

I am trying to calculate a GS1 check digit and have come up with the following code. The algorithm for calculating a check digit is:


  1. 反转条形码

  2. 删除最后一位数字(计算的校验位)

  3. 将数字与第一,第三,第五等相加数字乘以3,偶数乘以1。

  4. 从等于或大于10的最接近整数倍或更高整数中减去总和

  1. Reverse the barcode
  2. Drop the last digit (calculated check digit)
  3. Add the digits together with first, third, fifth, e.t.c. digit multiplied by 3 and even digits multiplied by 1.
  4. Subtract the sum from nearest equal or higher multiple of ten

听起来很简单,但是我想出的解决方案似乎不太优雅。它确实可以工作,但是我想知道是否有一种更优雅的方式来编写它。

It sounds simple typed out but the solution I came up with seemed a bit inelegant. It does work but I want to know if there is a more elegant way of writing this.

(defn abs "(abs n) is the absolute value of n" [n]
  (cond
   (not (number? n)) (throw (IllegalArgumentException.
                 "abs requires a number"))
   (neg? n) (- n)
   :else n))

(defn sum-seq "adds (first number times 3) with (second number)"
  [coll]
  (+ 
   (* (first coll) 3)
   (second coll)))

(defn sum-digit
  [s]
  (reduce +
  (map sum-seq
  (partition 2 2 '(0) 
  (map #(Integer/parseInt %)
  (drop 2 (clojure.string/split (clojure.string/reverse s) #"")))))))

(defn mod-higher10 "Subtracts the sum from nearest equal or higher multiple of ten"
  [i]
  (if (zero? (rem i 10))
    0
    (- 10(rem i 10))))

(defn check-digit "calculates a GS1 check digit"
  [s]
  (mod-higher10 
   (sum-digit s)))

(= (check-digit "7311518182472") 2)
(= (check-digit "7311518152284") 4)
(= (check-digit "7311518225261") 1)
(= (check-digit "7311518241452") 2)
(= (check-digit "7311518034399") 9)
(= (check-digit "7311518005955") 5)
(= (check-digit "7311518263393") 3)
(= (check-digit "7311518240943") 3)
(= (check-digit "00000012345687") 7)
(= (check-digit "012345670") 0)


推荐答案

(defn check-digit 
  [s] 
  (let [digits        (map #(Integer/parseInt (str %)) s)
        [chk & body]  (reverse digits)
        sum           (apply + (map * body (cycle [3 1])))
        moddiff       (mod (- 10 sum) 10)]
       moddiff))  

此实现使用了我意识到的两个Clojure习语:

This implementation uses two clojure idioms I am conscious of:


  • let 来管理本地分解(和重用)

  • map 和第二个集合,是一个无限懒惰序列,与问题相邻。

  • let to manage local decomposition (and reuse)
  • map with a second collection, being an infinite lazy sequence 'adjacent' to the problem.

-structures列表,这样很容易将检查谓词写为(= moddiff chk)

Also de-structures list so that would be easy to write the checking predicate as (= moddiff chk).

这篇关于在Clojure中计算GS1校验位的更多惯用方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆