# Calculate ISBN-13 check digit

Write a function which, given the first 12 digits of an ISBN-13 code, will calculate the entire ISBN via calculating and appending an appropriate check digit.

Your function's input is a string containing the first 12 digits of the ISBN. Its output is a string containing all 13 digits.

## Formal specification

Write a function which, when given a string s consisting entirely of exactly 12 decimal digits (and no other characters), returns a string t with the following properties:

• t consists of exactly 13 decimal digits (and no other characters);
• s is a prefix of t;
• the sum of all digits in odd positions in t (i.e. the first, third, fifth, etc.), plus three times the sum of all digits in even positions in t (i.e. the second, fourth, sixth, etc), is a multiple of 10.

## Example / test case

Input
978030640615

Output
9780306406157

## Victory condition

As a challenge, the shortest answer wins.

• Are input and output supposed to contain dashes or only the digits? – sepp2k Feb 1 '11 at 19:57
• Updated the description, the input and output are only the digits – Kevin Brown Feb 1 '11 at 20:06
• Is outputting the full ISBN-13 acceptable as well? – Mr. Llama Mar 2 '12 at 19:43
• Note that questions should really be self contained, so it would be helpful to include a description of the algorithm here. – FlipTack Nov 19 '17 at 10:01
• For me above post is poor of example test... There would be at last 10 isbn and one of that has to return 0 as last digit... – user58988 Mar 9 '19 at 19:34

# JavaScript, 57 bytes

f=s=>s+(10-s.split.reduce((a,b,i)=>a+b*(3-i%2*2),0)%10)


You can invoke it like this:

f("978030640615")


Effectively, it goes through each (digit, index) pair (b, i), and works out i % 2 (is i odd?), multiplies it by 2, and subtracts it from 3. Take a look at this:

For odd numbers:

• (i % 2) is 1
• ((i % 2) * 2) is 2
• 3 - ((i % 2) * 2) is 1

For even numbers:

• (i % 2) is 0
• ((i % 2) * 2) is 0
• 3 - ((i % 2) * 2) is 3

And so we have now generated the correct multipliers. From there it is simple, just add the current accumulator value, initialised at 0, to the current character multiplied by this generated multiplier. JavaScript automatically casts string to numbers when you do this multiplication.

Calculating the last digit is done by taking the last digit (by computing the value modulo 10), and subtracting this from 10.

# 05AB1E, 11 bytes

SιO3*+θTα«


Explanation:

S            # Convert the (implicit) input to a list of digits
#  i.e. 978030640615 → [9,7,8,0,3,0,6,4,0,6,1,5]
ι           # Uninterleave it
#  → [[9,8,3,6,0,1],[7,0,0,4,6,5]]
O          # Sum each inner list
#  → [27,22]
# Push them both separated to the stack
3*       # Multiply the top one by 3
#  → 66
+      # Sum them together
#  → 93
θ     # Only leave the last digit
#  → 3
Tα   # Take the absolute difference of this digit with 10
#  → 7
«  # And append this digit to the (implicit) input
#  → 9780306406157
# (after which it is output implicitly as result)


# MATLAB - 82 chars

function c(i)
[i num2str(mod(10-mod(sum(str2num(i(:)).*repmat([1;3],6,1)),10),10))]


## R, 147 characters

f=function(v){s=as.numeric(strsplit(v,"")[]);t=0;for(i in 1:12)if(i%%2==0)t=t+s[i]*3 else t=t+s[i];paste(v,(10-(t%%10))%%10,collapse="",sep="")}


Usage:

f("978030640615")
 "9780306406157"


# J, 25

,[:":10|0(-+/)"."0*1 3$~#   f =: ,[:":10|0(-+/)"."0*1 3$~#
f '978030640615'
9780306406157


Javascript: 73 71 chars

function _(b){for(i=s=0;12>i;)s+=((i*2&2)+1)*b[i++];return b+(10-s%10)}


Usage:

_('978030640615') //"9780306406157"

• Why not define _ as an arrow function too? That saves quite a few characters :) – Max Mar 9 '19 at 21:20

Clojure 264 -> 241 characters:

(defn s [a b] (let [c (count a)] (if (= 0 c) b (s (rest a) (+ b (* (if (= 0 (m c 2)) 1 3) (first a)))))))
(defn m [a b] (let [f (mod a b)] (if (= f 10) 0 f)))
(defn c [a] (str a (m (- 10 (m (s (map #(read-string %) (map str a)) 0) 10)) 10)))


Usage

(c "978030640615")


Non minified:

(defn sum [collection total]
(let [len (count collection)]
(if (= 0 len)
total
(sum (rest collection)
(+ total
(* (if (= 0 (mod len 2)) 1 3)
(first collection)))))))

(defn mods [a b]
(let [f (mod a b)]
(if (= f 10)
0
f)))

(defn create [isbn]
(str isbn
(mods (- 10 (mods (sum (map #(read-string %) (map str isbn)) 0) 10)) 10)))


Usage:

(create "978030640615")


New to Clojure so I have to believe that can be knocked down.

proc f c {lmap a\ b [split $c {}] {incr d [expr$a+3*$b]};list$c[expr -$d%10]}  # Tcl, 87 bytes proc C s {lmap c [split$s ""] {incr t [expr [incr i]%2?$c:3*$c]}
list $s[expr -$t%10]}


Try it online!

# Tcl, 64 bytes

proc C s {list $s[expr ([regsub -all (.)(.)$s {-\1-3*\2}])%10]}


Try it online!

# Husk, 16 bytes

S:(→sΣz¤*or;¢"97


Try it online!

### Explanation

Instead of subtracting the sum from 10 I use negated coefficients, the rest is pretty self-explanatory:

S:(              )  -- apply the following function and append result to itself:
→s               -- mod 10 / last digit
Σ              -- sum
z      ¢"97   -- zip input with ['9','7','9','7'...] under:
¤ (r;)       --   convert both chars to number, then
*           --   multiply


1 INPUT T$:FOR I=1 TO 12 STEP 2:O=O+VAL(MID$(T$,I,1)):E=E+3*VAL(MID$(T$,I+1,1)):NEXT:PRINT 10-(O+E) MOD 10  It ain't pretty, but it works. ? 978030640615 7  # J, 21 bytes ,10":@|1#."."+*9 7$~#


Try it online!

### How it works

,10":@|1#."."+*9 7$~# # Take length of input 9 7$~   Repeat 9 7 that many times
"."+*        Multiply (elementwise) to the digits
1#.             Sum
10   |                Modulo 10
":@                 Format to string
,                      Append to the end of the input string


The negative of a + 3b + c + 3d + ... modulo 10 is equal to 9a + 7b + 9c + 7d + ... modulo 10.

# Kotlin, 1201088377 69 bytes

{s->s+(10-(s.map{it.toInt()-48}.chunked(2).sumBy{it+3*it})%10)}


Try it online!

Thanks to @ovs for removing 8 bytes!!

• I don't think you need .absoluteValue as all digits are non-negative, So this works for 69 bytes. – ovs Mar 5 '19 at 16:15
• you're right! thanks! I removed it after, to get it to 77 bytes, but your edit was much better – Adam Mar 5 '19 at 16:21

# ><>, 24 bytes

0{:9)68**-:nl2%2*7+*+a%!


Try it online!

Explanation

0                      !  # initiates sum (final digit) as 0
{                        # get the next digit
:9)68**-                # convert from char to int for any iteration except the last
:n              # print the digit
l2%2*7+*      # multiply the digit by either 9 or 7 alternately
a%   # mod sum by 10


# Perl 5, 48 bytes

sub f{"@_"=~s/(.)(.)/$t-=$1+3*$2/ger;"@_".$t%10}


Try it online!

Doing this as a full program would be shorter:

### Perl 5-p, 31 bytes

s/(.)(.)/$\-=$1+3*$2/ger;$\%=10


Try it online!

## Python

>>>r=input()
>>>a=0
>>>for x in r[::2]:
a+=int(x)
>>>for x in r[1::2]:
a+=int(x)*3
>>>a=(10-(a%10))%10
print(r+str(a))

• I've added the language name to your answer; I was going to add a character count too but it looks like you've cut and paste from the REPL. Could you change this so it's a function as requested in the question and add a character count? – Gareth Oct 29 '12 at 12:53