【问题标题】:How can I get the first two digits of a number?如何获取数字的前两位?
【发布时间】:2016-12-21 20:23:15
【问题描述】:

我想检查 Python 中数字的前两位。像这样的:

for i in range(1000):

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

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

是否有检查数字前两位数字的命令?我想避免像if(i>149 and i<160):...这样的命令

【问题讨论】:

  • "数字的前两个数字" -- 你的意思是说"数字的前两个数字" ??
  • 转换为字符串,检查前两个符号是否为“15”。
  • 对不起 Dinesh Pundkar。是的,我的意思是数字的前两位...
  • str(i).startswith(str(15))str(i).startswith('15')

标签: python


【解决方案1】:

将 O(n) 时间解决方案与其他答案中提供的“恒定时间”O(1) 解决方案进行比较表明,如果 O(n) 算法足够快,n 可能在它比慢 O(1) 慢之前必须变得非常大。

strings 版本约为。对于 20 位或更少位数的数字,比“数学”版本快 60%。只有当位数接近 200 位数

时,它们才会变得更接近
# 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)

【讨论】:

    【解决方案2】:

    您可以将您的数字转换为字符串并像这样使用列表切片:

    int(str(number)[:2])
    

    输出:

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

    【讨论】:

    • 我最初来这里是为了一个基于数学的答案,但发现这个基于字符串的解决方案比提供的其他基于数学的答案更快。 see %timeit results below
    • 四舍五入呢?
    【解决方案3】:

    前两个答案都至少具有 O(n) 时间复杂度,并且字符串转换也具有 O(n) 空间复杂度。以下是恒定时间和空间的解决方案:

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

    功能:

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

    输出:

    >>> 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
    

    如果您输入的数字可能比您想要的少,您将需要添加一些检查。

    【讨论】:

    • 显然不是,因为您不能获取负值的日志。但由于我们只是查看数字,只需将其包装在 np.abs() 中即可。
    • 更重要的是,这 not 适用于例如1000和1; first_n_digits(1000,1) 返回10。这种方法总是有数字后面跟着很多零的问题。
    • 这比大 N 的字符串转换/列表切片要慢
    • 基于字符串的解决方案的时间和空间复杂度为 O(logN),而不是 O(n)。
    【解决方案4】:

    您可以使用正则表达式来测试匹配并捕获前两位数字:

    import re
    
    for i in range(1000):
        match = re.match(r'(1[56])', str(i))
    
        if match:
            print(i, 'begins with', match.group(1))
    

    正则表达式 (1[56]) 匹配 1 后跟 5 或 6,并将结果存储在第一个捕获组中。

    输出:

    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
    

    【讨论】:

    • 嗯,有些人用正则表达式做任何事情,即使这显然是一个巨大的矫枉过正......
    【解决方案5】:

    Dom's solution 实际上对 1000、1000000 等数字有问题。
    这是因为

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

    (结果 但是使用 math.log10() 就可以了。 (python 3.8)

    >>> math.log10(1000)
    3.0
    

    也许函数 log 和 log10 有不同的计算算法。

    固定功能是

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

    相关:Python math.log and math.log10 giving different results
    (我可能应该对 dom's answer 发表评论,但我没有足够的声誉)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-11
      • 2017-12-16
      • 1970-01-01
      • 2016-01-05
      • 2012-06-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多