How to take the nth digit of a number in python
You can do it with integer division and remainder methods
def get_digit(number, n): return number // 10**n % 10get_digit(987654321, 0)# 1get_digit(987654321, 5)# 6
The //
performs integer division by a power of ten to move the digit to the ones position, then the %
gets the remainder after division by 10. Note that the numbering in this scheme uses zero-indexing and starts from the right side of the number.
I was curious about the relative speed of the two popular approaches - casting to string and using modular arithmetic - so I profiled them and was surprised to see how close they were in terms of performance.
(My use-case was slightly different, I wanted to get all digits in the number.)
The string approach gave:
10000002 function calls in 1.113 seconds Ordered by: cumulative time ncalls tottime percall cumtime percall filename:lineno(function) 10000000 1.113 0.000 1.113 0.000 sandbox.py:1(get_digits_str) 1 0.000 0.000 0.000 0.000 cProfile.py:133(__exit__) 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
While the modular arithmetic approach gave:
10000002 function calls in 1.102 seconds Ordered by: cumulative time ncalls tottime percall cumtime percall filename:lineno(function) 10000000 1.102 0.000 1.102 0.000 sandbox.py:6(get_digits_mod) 1 0.000 0.000 0.000 0.000 cProfile.py:133(__exit__) 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
There were 10^7 tests run with a max number size less than 10^28.
Code used for reference:
def get_digits_str(num): for n_str in str(num): yield int(n_str)def get_digits_mod(num, radix=10): remaining = num yield remaining % radix while remaining := remaining // radix: yield remaining % radixif __name__ == '__main__': import cProfile import random random_inputs = [random.randrange(0, 10000000000000000000000000000) for _ in range(10000000)] with cProfile.Profile() as str_profiler: for rand_num in random_inputs: get_digits_str(rand_num) str_profiler.print_stats(sort='cumtime') with cProfile.Profile() as mod_profiler: for rand_num in random_inputs: get_digits_mod(rand_num) mod_profiler.print_stats(sort='cumtime')