51

I want to check the first two digits of a number in Python. Something like this:

for i in range(1000):

    if(first two digits of i == 15):
        print("15")

    elif(first two digits of i == 16):
        print("16")

Is there a command to check the first two digits of a number? I'd like to avoid commands like if(i>149 and i<160):...

ThisSuitIsBlackNot
  • 23,492
  • 9
  • 63
  • 110
John28
  • 723
  • 3
  • 8
  • 12

6 Answers6

102

You can convert your number to string and use list slicing like this:

int(str(number)[:2])

Output:

>>> number = 1520
>>> int(str(number)[:2])
15

You can turn this into a function to handle edge-cases, such as negative number.

def first_n_digits(num, n):
    num = abs(num)
    num_str = str(num)

    if n >= len(num_str):
        return num

    return int(num_str[:n])
Somu
  • 3,593
  • 6
  • 34
  • 44
ettanany
  • 19,038
  • 9
  • 47
  • 63
  • 3
    I originally came here for a math-based answer, but found this string-based solution is faster than the other math-based answer provided. [see %timeit results below](https://stackoverflow.com/questions/41271299/how-can-i-get-the-first-two-digits-of-a-number/56248048#56248048) – ChrisFreeman May 22 '19 at 01:14
  • what about rounding number ? – soheshdoshi Sep 16 '19 at 10:35
33

Both of the previous 2 answers have at least O(n) time complexity and the string conversion has O(n) space complexity too. Here's a solution for constant time and space:

num // 10 ** (int(math.log(num, 10)) - 1)

Function:

import math

def first_n_digits(num, n):
    return num // 10 ** (int(math.log(num, 10)) - n + 1)

Output:

>>> first_n_digits(123456, 1)
1
>>> first_n_digits(123456, 2)
12
>>> first_n_digits(123456, 3)
123
>>> first_n_digits(123456, 4)
1234
>>> first_n_digits(123456, 5)
12345
>>> first_n_digits(123456, 6)
123456

You will need to add some checks if it's possible that your input number has less digits than you want.

dom
  • 377
  • 3
  • 3
  • Obviously not since you cannot take logs of negative values. But since we are just looking at digits, just wrap it in np.abs() and then it works. – Astrid Oct 12 '18 at 08:45
  • 12
    More importantly, this does _not_ work for e.g. 1000 and 1; `first_n_digits(1000,1)` returns `10`. This method always has problems with digits followed by lots of zeros. – Astrid Oct 12 '18 at 08:58
  • 3
    this turns out to be slower than string conversion/list slicing for large N – noiivice Dec 03 '18 at 17:04
  • It's O(logN), not O(n) time and space complexity for string based solutions. – tejasvi88 Feb 22 '22 at 04:03
13

Comparing the O(n) time solution with the "constant time" O(1) solution provided in other answers goes to show that if the O(n) algorithm is fast enough, n may have to get very large before it is slower than a slow O(1).

The strings version is approx. 60% faster than the "maths" version for numbers of 20 or fewer digits. They become closer only when then number of digits approaches 200 digits

# the "maths" version
import math

def first_n_digits1(num, n):
    return num // 10 ** (int(math.log(num, 10)) - n + 1)

%timeit first_n_digits1(34523452452, 2)
1.21 µs ± 75 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit first_n_digits1(34523452452, 8)
1.24 µs ± 47.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

# 22 digits
%timeit first_n_digits1(3423234239472523452452, 2)
1.33 µs ± 59.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit first_n_digits1(3423234239472523452452, 15)
1.23 µs ± 61.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

# 196 digits
%timeit first_n_digits1(3423234239472523409283475908723908723409872390871243908172340987123409871234012089172340987734507612340981344509873123401234670350981234098123140987314509812734091823509871345109871234098172340987125988123452452, 39)
1.86 µs ± 21.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

# The "string" verions
def first_n_digits2(num, n):
    return int(str(num)[:n])

%timeit first_n_digits2(34523452452, 2)
744 ns ± 28.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit first_n_digits2(34523452452, 8)
768 ns ± 42.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

# 22 digits
%timeit first_n_digits2(3423234239472523452452, 2)
767 ns ± 33.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit first_n_digits2(3423234239472523452452, 15)
830 ns ± 55.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

# 196 digits
%timeit first_n_digits2(3423234239472523409283475908723908723409872390871243908098712340987123401208917234098773450761234098134450987312340123467035098123409812314098734091823509871345109871234098172340987125988123452452, 39)
1.87 µs ± 140 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
ChrisFreeman
  • 5,831
  • 4
  • 20
  • 32
3

Dom's solution actualy has problems with numbers such as 1000, 1000000 etc.
This is because

>>> math.log(1000, 10)  
2.9999999999999996

(result < 3)
But using math.log10() makes it right. (python 3.8)

>>> math.log10(1000)
3.0

Perhaps functions log and log10 have different calculation algorithms.

Fixed function is

import math

def first_n_digits(num, n):
    return num // 10 ** (int(math.log10(num)) - n + 1)

Related: Python math.log and math.log10 giving different results
(I probably should have commented on dom's answer but I don't have enough reputation)

chalex2k
  • 31
  • 2
1

'If trying to obtain first 2 digits of a 4 digit number, then you can use the solution below:'

abs(number//100)

Josh
  • 11
  • 1
0

You can use a regular expression to test for a match and capture the first two digits:

import re

for i in range(1000):
    match = re.match(r'(1[56])', str(i))

    if match:
        print(i, 'begins with', match.group(1))

The regular expression (1[56]) matches a 1 followed by either a 5 or a 6 and stores the result in the first capturing group.

Output:

15 begins with 15
16 begins with 16
150 begins with 15
151 begins with 15
152 begins with 15
153 begins with 15
154 begins with 15
155 begins with 15
156 begins with 15
157 begins with 15
158 begins with 15
159 begins with 15
160 begins with 16
161 begins with 16
162 begins with 16
163 begins with 16
164 begins with 16
165 begins with 16
166 begins with 16
167 begins with 16
168 begins with 16
169 begins with 16
ThisSuitIsBlackNot
  • 23,492
  • 9
  • 63
  • 110