如果我想找到一个数的数字之和,例如:
- 输入:
932
- 输出:
14
,即(9 + 3 + 2)
怎样最快地实现这个功能呢?
我的本能反应是:
sum(int(digit) for digit in str(number))
我在网上找到了这个:
sum(map(int, str(number)))
哪种方法最适合用于速度,还有其他更快的方法吗?
你发布的两行代码都没问题,但你可以使用纯整数计算,这将是最有效的:
def sum_digits(n):
s = 0
while n:
s += n % 10
n //= 10
return s
或使用 divmod
函数:
def sum_digits2(n):
s = 0
while n:
n, remainder = divmod(n, 10)
s += remainder
return s
稍微快一点的方法是使用单个赋值语句:
def sum_digits3(n):
r = 0
while n:
r, n = r + n % 10, n // 10
return r
> %timeit sum_digits(n)
1000000 loops, best of 3: 574 ns per loop
> %timeit sum_digits2(n)
1000000 loops, best of 3: 716 ns per loop
> %timeit sum_digits3(n)
1000000 loops, best of 3: 479 ns per loop
> %timeit sum(map(int, str(n)))
1000000 loops, best of 3: 1.42 us per loop
> %timeit sum([int(digit) for digit in str(n)])
100000 loops, best of 3: 1.52 us per loop
> %timeit sum(int(digit) for digit in str(n))
100000 loops, best of 3: 2.04 us per loop
如果你想将数字的每一位相加,直到得到一个个位数(这是我最喜欢的9的倍数的特性之一),那么你可以这样做:
如果你希望保持数字的每一位相加,直到得到个位数(这是我最喜欢9的倍数的特点之一),你可以这样做:
def digital_root(n):
x = sum(int(digit) for digit in str(n))
if x < 10:
return x
else:
return digital_root(x)
实际上这本身就相当快...
%timeit digital_root(12312658419614961365)
10000 loops, best of 3: 22.6 µs per loop
digital_root(n) = n-9*(n-1//9)
。 - reschun%9
- Toby Speight(n - 1) % 9 + 1
。 - Aivar Paalberg我在一个解决问题挑战网站上发现了这个。不是我的,但它有效。
num = 0 # replace 0 with whatever number you want to sum up
print(sum([int(k) for k in str(num)]))
def digit_sum(n):
num_str = str(n)
sum = 0
for i in range(0, len(num_str)):
sum += int(num_str[i])
return sum
在完成一些Codecademy的挑战时,我解决了这个问题:
def digit_sum(n):
digits = []
nstr = str(n)
for x in nstr:
digits.append(int(x))
return sum(digits)
def sum_digits_math(n):
r = 0
while n:
r, n = r + n % 10, n // 10
return r
对于长度大于30位的大数,使用字符串域:
def sum_digits_str_fast(n):
d = str(n)
return sum(int(s) * d.count(s) for s in "123456789")
在20到30位数字之间,sum(map(int, str(n)))
是最快的。这是下面图表中紫色线条所代表的(点击这里放大查看)。
随着输入数字越来越大,使用数学方法的性能会变得越来越差,但每种在字符串域中工作的方法似乎都会按照输入长度线性扩展。生成这些图表所使用的代码在这里,我在macOS上使用的是CPython 3.10.6。
这是一个没有任何循环或递归但只适用于非负整数的解决方案(Python3):
def sum_digits(n):
if n > 0:
s = (n-1) // 9
return n-9*s
return 0
试试这个
print(sum(list(map(int,input("Enter your number ")))))
因此,一个数的各位数字之和是每个位数系数的总和。a × 10^p + b × 10^p-1 .. z × 10^0
import math
def add_digits(n):
# Assume n >= 0, else we should take abs(n)
if 0 <= n < 10:
return n
r = 0
ndigits = int(math.log10(n))
for p in range(ndigits, -1, -1):
d, n = divmod(n, 10 ** p)
r += d
return r
这实际上是与接受答案中连续除以10的过程相反。考虑到与接受答案相比,此函数中存在额外的计算,因此不难发现此方法的性能较差:它大约慢3.5倍,而且比...慢两倍
sum(int(x) for x in str(n))
% echo; ( time (nice echo 33785139853861968123689586196851968365819658395186596815968159826259681256852169852986 \
| mawk2 'gsub(//,($_)($_)($_))+gsub(//,($_))+1' | pvE0 \
| mawk2 '
function __(_,___,____,_____) {
____=gsub("[^1-9]+","",_)~""
___=10
while((+____<--___) && _) {
_____+=___*gsub(___,"",_)
}
return _____+length(_) }
BEGIN { FS=OFS=ORS
RS="^$"
} END {
print __($!_) }' )| pvE9 ) | gcat -n | lgp3 ;
in0: 173MiB 0:00:00 [1.69GiB/s] [1.69GiB/s] [<=> ]
out9: 11.0 B 0:00:09 [1.15 B/s] [1.15 B/s] [<=> ]
in0: 484MiB 0:00:00 [2.29GiB/s] [2.29GiB/s] [ <=> ]
( nice echo | mawk2 'gsub(//,($_)($_)($_))+gsub(//,($_))+1' | pvE 0.1 in0 | )
8.52s user 1.10s system 100% cpu 9.576 total
1 2822068024
% echo; ( time ( nice echo 33785139853861968123689586196851968365819658395186596815968159826259681256852169852986 \
\
| mawk2 'gsub(//,($_)($_)($_))+gsub(//,($_))+1' | pvE0 \
| gtr -d '\n' \
\
| python3 -c 'import math, os, sys;
[ print(sum(int(digit) for digit in str(ln)), \
end="\n") \
\
for ln in sys.stdin ]' )| pvE9 ) | gcat -n | lgp3 ;
in0: 484MiB 0:00:00 [ 958MiB/s] [ 958MiB/s] [ <=> ]
out9: 11.0 B 0:00:35 [ 317miB/s] [ 317miB/s] [<=> ]
( nice echo | mawk2 'gsub(//,($_)($_)($_))+gsub(//,($_))+1' | pvE 0.1 in0 | )
35.22s user 0.62s system 101% cpu 35.447 total
1 2822068024
这已经有点慷慨了。在这个2.82 GB的大型合成测试用例中,它要慢19.2倍。
% echo; ( time ( pvE0 < testcases_more108.txt | mawk2 'function __(_,___,____,_____) { ____=gsub("[^1-9]+","",_)~"";___=10; while((+____<--___) && _) { _____+=___*gsub(___,"",_) }; return _____+length(_) } BEGIN { FS=RS="^$"; CONVFMT=OFMT="%.20g" } END { print __($_) }' ) | pvE9 ) |gcat -n | ggXy3 | lgp3;
in0: 284MiB 0:00:00 [2.77GiB/s] [2.77GiB/s] [=> ] 9% ETA 0:00:00
out9: 11.0 B 0:00:11 [1016miB/s] [1016miB/s] [<=> ]
in0: 2.82GiB 0:00:00 [2.93GiB/s] [2.93GiB/s] [=============================>] 100%
( pvE 0.1 in0 < testcases_more108.txt | mawk2 ; )
8.75s user 2.36s system 100% cpu 11.100 total
1 3031397722
% echo; ( time ( pvE0 < testcases_more108.txt | gtr -d '\n' | python3 -c 'import sys; [ print(sum(int(_) for _ in str(__))) for __ in sys.stdin ]' ) | pvE9 ) |gcat -n | ggXy3 | lgp3;
in0: 2.82GiB 0:00:02 [1.03GiB/s] [1.03GiB/s] [=============================>] 100%
out9: 11.0 B 0:03:32 [53.0miB/s] [53.0miB/s] [<=> ]
( pvE 0.1 in0 < testcases_more108.txt | gtr -d '\n' | python3 -c ; )
211.47s user 3.02s system 100% cpu 3:32.69 total
1 3031397722
—————————————————————
更新:该概念的本地Python3代码 - 即使是在我可怕的Python技能下,我也看到了4倍的加速:
% echo; ( time ( pvE0 < testcases_more108.txt \
\
|python3 -c 'import re, sys;
print(sum([ sum(int(_)*re.subn(_,"",__)[1]
for _ in [r"1",r"2", r"3",r"4",
r"5",r"6",r"7",r"8",r"9"])
for __ in sys.stdin ]))' |pvE9))|gcat -n| ggXy3|lgp3
in0: 1.88MiB 0:00:00 [18.4MiB/s] [18.4MiB/s] [> ] 0% ETA 0:00:00
out9: 0.00 B 0:00:51 [0.00 B/s] [0.00 B/s] [<=> ]
in0: 2.82GiB 0:00:51 [56.6MiB/s] [56.6MiB/s] [=============================>] 100%
out9: 11.0 B 0:00:51 [ 219miB/s] [ 219miB/s] [<=> ]
( pvE 0.1 in0 < testcases_more108.txt | python3 -c | pvE 0.1 out9; )
48.07s user 3.57s system 100% cpu 51.278 total
1 3031397722
即使是较小的测试用例也实现了1.42倍的加速:
echo; ( time (nice echo 33785139853861968123689586196851968365819658395186596815968159826259681256852169852986 \
| mawk2 'gsub(//,($_)($_)$_)+gsub(//,$_)+1' ORS='' | pvE0 | python3 -c 'import re, sys; print(sum([ sum(int(_)*re.subn(_,"",__)[1] for _ in [r"1",r"2", r"3",r"4",r"5",r"6",r"7",r"8",r"9"]) for __ in sys.stdin ]))' | pvE9 )) |gcat -n | ggXy3 | lgp3
in0: 484MiB 0:00:00 [2.02GiB/s] [2.02GiB/s] [ <=> ]
out9: 11.0 B 0:00:24 [ 451miB/s] [ 451miB/s] [<=> ]
( nice echo | mawk2 'gsub(//,($_)($_)$_)+gsub(//,$_)+1' ORS='' | pvE 0.1 in0)
20.04s user 5.10s system 100% cpu 24.988 total
1 2822068024
timeit
模块允许以编程方式计时代码,也可以在命令行上计时短代码片段。此外,请注意您假设输入为字符串,而不是Python(任意大小)整数。 - Karl Knechtel