I've been a zone leader with DZone since 2008, and I'm crazy about community. Every day I get to work with the best that JavaScript, HTML5, Android and iOS has to offer, creating apps that truly make at difference, as principal front-end architect at Avego. James is a DZone Zone Leader and has posted 639 posts at DZone. You can read more from them at their website. View Full User Profile

Thursday Code Puzzler: ISBN Validator

04.04.2013
| 3383 views |
  • submit to reddit

Thursday is code puzzler day here at DZone. The idea is simple: solve the coding problem as efficiently as you can, in any language or framework that you find suitable.

Note: Even though there really is nothing stopping you from finding a solution to this on the internet, try to keep honest, and come up with your own answer.  It's all about the participation!

Do you have code puzzlers that you'd like to share with the DZone community?  If so, please submit here. 

Check if a given string is an ISBN number

Write a method that will take a string parameter and check if it conforms to the ISBN-13 specification as detailed in Wikipedia. 

The calculation of an ISBN-13 check digit begins with the first 12 digits of the thirteen-digit ISBN (thus excluding the check digit itself). Each digit, from left to right, is alternately multiplied by 1 or 3, then those products are summedmodulo10 to give a value ranging from 0 to 9. Subtracted from 10, that leaves a result from 1 to 10. A zero (0) replaces a ten (10), so, in all cases, a single check digit results.

Formally, the ISBN-13 check digit calculation is:
x_{13} = \big(10 - \big(x_1 + 3x_2 + x_3 + 3x_4 + \cdots + x_{11} + 3x_{12}\big) \,\bmod\, 10\big) \,\bmod\, 10.

Catch up on all our previous puzzlers here.

 

Comments

Vijay Nathani replied on Thu, 2013/04/04 - 4:08am

Groovy
def isISBN13Valid(number) {
	def even = false
	def sum  = number.toList().subList(0, number.size() - 1).sum { ((even=!even)?1:3) * it.toInteger() } 
	number[-1..-1].toInteger() == (10 - sum % 10)
}
assert isISBN13Valid("9780306406157")


sun east replied on Thu, 2013/04/04 - 6:37am

Scala:

/**
*/
def isISBN13Valid(isbn: String):Boolean= isbn.size == 13&&
  isbn.zipWithIndex.map{case(c,i)=>c*(i%2*2+1)}.sum%10 == 0

sun east replied on Thu, 2013/04/04 - 9:54am

Python 2.7(without length checking):

def isISBN13Valid(isbn):
    return sum(int(c)*(i%2*2+1) for i,c in enumerate(isbn))%10==0

sun east replied on Thu, 2013/04/04 - 6:24am

Given an ISBN string x0x1x2..x12, instead of checking the result of

(x0-'0' + 3*(x1-'0') + ... + x12-'0')%10 == 0 

We only need to check the result of

(x0 + 3*x1+ x2 + ... + 3*x11 + x12)%10 == 0

since '0'.toInt == 48 and 7*48 + 3*6*48 = 1200 which is a multiple of 10.


Vijay Nathani replied on Thu, 2013/04/04 - 12:39pm in response to: sun east

Right. So the improved code in Groovy can be

def isISBN13Valid(number) {
	def odd = false
	(number.toList().sum { ((odd=!odd)?1:3) * it.toInteger() }) % 10 == 0
}
assert isISBN13Valid("9780306406157")

Frank Dietrich replied on Thu, 2013/04/04 - 2:11pm

Java
    public static boolean isISBN13Valid(String isbn) {
        byte[] buffer = isbn.getBytes();
        // take the check digit (the mod 10 remainder)
        int check = buffer[12];
        for (int i = 0; i < 12;) {
            // add digits with a simple value
            check += buffer[i++];
            // add digits with a triple value
            check += buffer[i++] * 3;
        }
        return check % 10 == 0;
    }

Skeeve Magick replied on Thu, 2013/04/04 - 2:55pm

Perl:

sub isValidISBN13 {
   ($_)=@_;
   return /^\d{13}$/ && s/(.)(.)/$1+3*$2+/g && (eval)%10==0
}
print isValidISBN13("9783404603466");

Alex Oscherov replied on Sat, 2013/04/06 - 9:52pm

 In Haskell:

mask = let op = (take 12) . cycle in op [1,3]
isbnCheckSum = sum . (zipWith (*) mask)
isISBN x = 10 - ((isbnCheckSum (init x)) `mod` 10)  == last x

Rob Van Der Woude replied on Wed, 2013/04/10 - 2:22pm

 Windows batch:


@ECHO OFF
CALL :ValidateISBN "9780306406157"
CALL :ValidateISBN "9780306406158"
GOTO:EOF

:ValidateISBN
SETLOCAL ENABLEDELAYEDEXPANSION
SET ISBN=%~1
SET Multiplier=1
SET Checksum=0
FOR /L %%A IN (0,1,11) DO (
   SET Digit=!ISBN:~%%A,1!
   SET /A Checksum += !Multiplier! * !Digit!
   SET /A Multiplier = 4 - !Multiplier!
)
SET /A "Checksum = ( 10 - ( %Checksum% %% 10 ) ) %% 10"
IF %Checksum% EQU %ISBN:~12,1% (
   ECHO %~1 is a valid ISBN
) ELSE (
   ECHO %~1 is NOT a valid ISBN
)
ENDLOCAL
GOTO:EOF

Camilo Rivera replied on Mon, 2013/11/04 - 5:50am

Some Ruby:

def valid_isbn?(isbn)
	isbn.length == 13 && isbn[-1].to_i == (10-isbn[0...-1].split(//).map(&:to_i).each_with_index.map{|v,i| i%2==0 ? v : v*3 }.reduce(&:+) % 10) % 10 
end

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.