Split an integer into digits to compute an ISBN checksum

Question:

I’m writing a program which calculates the check digit of an ISBN number. I have to read the user’s input (nine digits of an ISBN) into an integer variable, and then multiply the last digit by 2, the second last digit by 3 and so on. How can I “split” the integer into its constituent digits to do this? As this is a basic homework exercise I am not supposed to use a list.

Asked By: zequzd

||

Answers:

Just create a string out of it.

myinteger = 212345
number_string = str(myinteger)

That’s enough. Now you can iterate over it:

for ch in number_string:
    print ch # will print each digit in order

Or you can slice it:

print number_string[:2] # first two digits
print number_string[-3:] # last three digits
print number_string[3] # forth digit

Or better, don’t convert the user’s input to an integer (the user types a string)

isbn = raw_input()
for pos, ch in enumerate(reversed(isbn)):
    print "%d * %d is %d" % pos + 2, int(ch), int(ch) * (pos + 2)

For more information read a tutorial.

Answered By: nosklo
list_of_ints = [int(i) for i in str(ISBN)]

Will give you a ordered list of ints. Of course, given duck typing, you might as well work with str(ISBN).

Edit: As mentioned in the comments, this list isn’t sorted in the sense of being ascending or descending, but it does have a defined order (sets, dictionaries, etc in python in theory don’t, although in practice the order tends to be fairly reliable). If you want to sort it:

list_of_ints.sort()

is your friend. Note that sort() sorts in place (as in, actually changes the order of the existing list) and doesn’t return a new list.

Answered By: mavnn
while number:
    digit = number % 10

    # do whatever with digit

    # remove last digit from number (as integer)
    number //= 10

On each iteration of the loop, it removes the last digit from number, assigning it to digit.
It’s in reverse, starts from the last digit, finishes with the first

Answered By: Alexandru Nedelcu

How about a one-liner list of digits…

ldigits = lambda n, l=[]: not n and l or l.insert(0,n%10) or ldigits(n/10,l)
Answered By: Lord British

On Older versions of Python…

map(int,str(123))

On New Version 3k

list(map(int,str(123)))
Answered By: st0le

Convert it to string and map over it with the int() function.

map(int, str(1231231231))
Answered By: Evgeny

Recursion version:

def int_digits(n):
    return [n] if n<10 else int_digits(n/10)+[n%10]
Answered By: chyanog

Converting to str is definitely slower then dividing by 10.

map is sligthly slower than list comprehension:

convert to string with map 2.13599181175
convert to string with list comprehension 1.92812991142
modulo, division, recursive 0.948769807816
modulo, division 0.699964046478

These times were returned by the following code on my laptop:

foo = """
def foo(limit):
    return sorted(set(map(sum, map(lambda x: map(int, list(str(x))), map(lambda x: x * 9, range(limit))))))

foo(%i)
"""

bar = """
def bar(limit):
    return sorted(set([sum([int(i) for i in str(n)]) for n in [k *9 for k in range(limit)]]))

bar(%i)
"""

rac = """
def digits(n):
    return [n] if n<10 else digits(n / 10)+[n %% 10]

def rabbit(limit):
    return sorted(set([sum(digits(n)) for n in [k *9 for k in range(limit)]]))

rabbit(%i)
"""

rab = """
def sum_digits(number):
  result = 0
  while number:
    digit = number %% 10
    result += digit
    number /= 10
  return result

def rabbit(limit):
    return sorted(set([sum_digits(n) for n in [k *9 for k in range(limit)]]))

rabbit(%i)
"""


import timeit

print "convert to string with map", timeit.timeit(foo % 100, number=10000)
print "convert to string with list comprehension", timeit.timeit(bar % 100, number=10000)
print "modulo, division, recursive", timeit.timeit(rac % 100, number=10000)
print "modulo, division", timeit.timeit(rab % 100, number=10000)
Answered By: bpgergo

Use the body of this loop to do whatever you want to with the digits

for digit in map(int, str(my_number)):
Answered By: shadowfox

I have made this program and here is the bit of code that actually calculates the check digit in my program

    #Get the 10 digit number
    number=input("Please enter ISBN number: ")

    #Explained below
    no11 = (((int(number[0])*11) + (int(number[1])*10) + (int(number[2])*9) + (int(number[3])*8) 
           + (int(number[4])*7) + (int(number[5])*6) + (int(number[6])*5) + (int(number[7])*4) +
           (int(number[8])*3) + (int(number[9])*2))/11)

    #Round to 1 dp
    no11 = round(no11, 1)

    #explained below
    no11 = str(no11).split(".")

    #get the remainder and check digit
    remainder = no11[1]
    no11 = (11 - int(remainder))

    #Calculate 11 digit ISBN
    print("Correct ISBN number is " + number + str(no11))

Its a long line of code, but it splits the number up, multiplies the digits by the appropriate amount, adds them together and divides them by 11, in one line of code. The .split() function just creates a list (being split at the decimal) so you can take the 2nd item in the list and take that from 11 to find the check digit. This could also be made even more efficient by changing these two lines:

    remainder = no11[1]
    no11 = (11 - int(remainder))

To this:

    no11 = (11 - int(no11[1]))

Hope this helps 🙂

Answered By: Ben
(number/10**x)%10

You can use this in a loop, where number is the full number, x is each iteration of the loop (0,1,2,3,…,n) with n being the stop point. x = 0 gives the ones place, x = 1 gives the tens, x = 2 gives the hundreds, and so on. Keep in mind that this will give the value of the digits from right to left, so this might not be the for an ISBN but it will still isolate each digit.

Answered By: Pski17

Similar to this answer but more a more “pythonic” way to iterate over the digis would be:

while number:
    # "pop" the rightmost digit
    number, digit = divmod(number, 10)
Answered By: Jeremy Cantrell

Answer: 165

Method: brute-force! Here is a tiny bit of Python (version 2.7) code to count’em all.

from math import sqrt, floor
is_ps = lambda x: floor(sqrt(x)) ** 2 == x
count = 0
for n in range(1002, 10000, 3):
    if n % 11 and is_ps(sum(map(int, str(n)))):
        count += 1
        print "#%i: %s" % (count, n)
Answered By: dohmatob

Just assuming you want to get the i-th least significant digit from an integer number x, you can try:

(abs(x)%(10**i))/(10**(i-1))

I hope it helps.

Answered By: Ricardo Alejos

After own diligent searches I found several solutions, where each has advantages and disadvantages. Use the most suitable for your task.

All examples tested with the CPython 3.5 on the operation system GNU/Linux Debian 8.


Using a recursion

Code

def get_digits_from_left_to_right(number, lst=None):
    """Return digits of an integer excluding the sign."""

    if lst is None:
        lst = list()

    number = abs(number)

    if number < 10:
        lst.append(number)
        return tuple(lst)

    get_digits_from_left_to_right(number // 10, lst)
    lst.append(number % 10)

    return tuple(lst)

Demo

In [121]: get_digits_from_left_to_right(-64517643246567536423)
Out[121]: (6, 4, 5, 1, 7, 6, 4, 3, 2, 4, 6, 5, 6, 7, 5, 3, 6, 4, 2, 3)

In [122]: get_digits_from_left_to_right(0)
Out[122]: (0,)

In [123]: get_digits_from_left_to_right(123012312312321312312312)
Out[123]: (1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 1, 3, 1, 2, 3, 1, 2, 3, 1, 2)

Using the function divmod

Code

def get_digits_from_right_to_left(number):
    """Return digits of an integer excluding the sign."""

    number = abs(number)

    if number < 10:
        return (number, )

    lst = list()

    while number:
        number, digit = divmod(number, 10)
        lst.insert(0, digit)

    return tuple(lst)

Demo

In [125]: get_digits_from_right_to_left(-3245214012321021213)
Out[125]: (3, 2, 4, 5, 2, 1, 4, 0, 1, 2, 3, 2, 1, 0, 2, 1, 2, 1, 3)

In [126]: get_digits_from_right_to_left(0)
Out[126]: (0,)

In [127]: get_digits_from_right_to_left(9999999999999999)
Out[127]: (9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9)

Using a construction tuple(map(int, str(abs(number)))

In [109]: tuple(map(int, str(abs(-123123123))))
Out[109]: (1, 2, 3, 1, 2, 3, 1, 2, 3)

In [110]: tuple(map(int, str(abs(1412421321312))))
Out[110]: (1, 4, 1, 2, 4, 2, 1, 3, 2, 1, 3, 1, 2)

In [111]: tuple(map(int, str(abs(0))))
Out[111]: (0,)

Using the function re.findall

In [112]: tuple(map(int, re.findall(r'd', str(1321321312))))
Out[112]: (1, 3, 2, 1, 3, 2, 1, 3, 1, 2)

In [113]: tuple(map(int, re.findall(r'd', str(-1321321312))))
Out[113]: (1, 3, 2, 1, 3, 2, 1, 3, 1, 2)

In [114]: tuple(map(int, re.findall(r'd', str(0))))
Out[114]: (0,)

Using the module decimal

In [117]: decimal.Decimal(0).as_tuple().digits
Out[117]: (0,)

In [118]: decimal.Decimal(3441120391321).as_tuple().digits
Out[118]: (3, 4, 4, 1, 1, 2, 0, 3, 9, 1, 3, 2, 1)

In [119]: decimal.Decimal(-3441120391321).as_tuple().digits
Out[119]: (3, 4, 4, 1, 1, 2, 0, 3, 9, 1, 3, 2, 1)
Answered By: PADYMKO
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.