1

GTIN-13 チェック ディジット アルゴリズムを実装する効率的な方法を探しています。thisthisなどの関連する SO 投稿をいくつか見てきましたが、どちらの場合も効率は注目されていないようです。

簡単に言えば、このアルゴリズムは数値文字列 (123765 など) を取り、1 つおきに (右から左に) 1 または 3 を掛けて合計を計算し (so 5 * 1 + 6 * 3 + 7 * 1 + 3 * 3 + 2 * 1 + 1 * 3 = 44)、次に等しい最も近い 10 の倍数からこの合計を減算します。またはそれ以上をこの合計 (この場合は50 - 44 = 6) にして、最終的なチェック ディジット (ここでは 6) を導き出します。入力は 12 桁の長さであると予想されますが、それより短い場合は、左から 0 を単純に埋め込むことができます (123765実際には のように予想されます000000123765) が、結果は同じになります。

これを単純に実装すると、次のようになります。

gtin13 <- function(n) {
  s <- as.character(n)
  check.sum <- 0
  for (i in 1:nchar(s)) {
    digit <- substr(s, nchar(s) - i + 1, nchar(s) - i + 1)
    check.sum <- check.sum + as.numeric(digit) * ifelse(i %% 2, 1, 3)
  }
  10 - check.sum %% 10
}

ただし、これは for ループと、文字列への変換と数値への変換のため、非効率的です。例えば:

df <- data.frame(
  num <- sample(1:1000000, 100000, T)
)
system.time(cd <- vapply(df$num, gtin13, 0))

平均的なデスクトップで約 6 秒かかります。

この check.sum をより効率的に計算するにはどうすればよいですか?

4

3 に答える 3

0

もっとうまくやることができます。文字の代わりに整数を操作すると、効率が大幅に向上します。

gtim13Challenger <- function(n) {
    n <- as.integer(n)
    len <- as.integer(ceiling(log10(n)))
    digs <- n %/% as.integer(10^(0L:(len - 1L))) %% 10L
    if (len > 1L)
        digs[seq.int(2L,len,2L)] <- digs[seq.int(2L,len,2L)] * 3L
    10L - sum(digs) %% 10L
}

system.time(cd <- vapply(df$num, gtim13, 0))
user  system elapsed 
6.15    0.00    6.16 

system.time(cd2 <- vapply(df$num, gtim13Challenger, 0L))
user  system elapsed 
0.76    0.00    0.76 

all.equal(cd, cd2)
[1] TRUE
于 2018-07-30T21:00:07.703 に答える