我正在使用Luhn算法来查找I检查号。例如-输入- 12345678,输出- 2。我试图以最有效的方式,以及在最少的行可能。到目前为止,我写了这个:
ID = input("Enter your first 8 digits of your id : ")
print(10 - sum(map(lambda a: a if a <= 9 else int(str(a)[0]) + int(str(a)[1]), [int(ID[i]) if i % 2
== 0 else int(ID[i]) * 2 for i in range(8)])) % 10) # if digit is 0 prints 10我对int字符串转换不满意。但我在寻求任何改善。
发布于 2021-05-15 02:15:38
欢迎来到StackOverflow!
超短,但有依赖性
如果您可以依赖外部依赖项,请查看luhn package。您可以使用pip install luhn安装它,然后您的程序变成:
from luhn import generate
ID = input("Enter your first 8 digits of your id : ")
print(generate(ID))再干净不过了。
更改您的代码
但假设您不想使用第三方包。让我们首先将您的代码放在一个函数中,并将其格式化:
def luhn(number):
return (
10 - sum(
map(
lambda a: a if a <= 9 else int(str(a)[0]) + int(str(a)[1]),
[
int(number[i])
if i % 2 == 0
else int(number[i]) * 2
for i in range(8)
]
)
) % 10
)步骤1:list到生成器
您可以简单地用一个generator expression替换您的列表理解,以使它更快一些,因为您不需要首先构建整个列表:
def luhn(number):
return (
10 - sum(
map(
lambda a: a if a <= 9 else int(str(a)[0]) + int(str(a)[1]),
( # <--- changed this
int(number[i])
if i % 2 == 0
else int(number[i]) * 2
for i in range(8)
) # <--- changed this
)
) % 10
)第2步:摆脱map
我个人不喜欢在您还需要编写lambda时使用map。它扼杀了map的两个用途:更简单的代码和快速、C-速度的执行。
例如,map(int, myseq)是伟大的,非常快和干净。但是map(lambda x: int(x), myseq)很麻烦(你必须给myseq条目起一个名字x )和慢(因为lambda不能从C类内置函数的速度中受益)。在这种情况下,我认为int(x) for x in myseq读起来要好得多。
将其应用于以前的功能:
def luhn(number):
return (
10 - sum(
a if a <= 9 else int(str(a)[0]) + int(str(a)[1])
for a in (
int(number[i])
if i % 2 == 0
else int(number[i]) * 2
for i in range(8)
) # bonus: we have one less indentation level!
) % 10
)第三步:去掉一个if-else
在第二个for循环中,我们有x if i % 2 == 0 else x * 2,其中有x = int(number[i])。但是,由于i % 2要么是0,要么是1,所以您可以从中受益并编写x * (1 + i%2)。因此,我们的职能是:
def luhn(number):
return (
10 - sum(
a if a <= 9 else int(str(a)[0]) + int(str(a)[1])
for a in (int(number[i]) * (1 + i%2) for i in range(8))
) % 10
)越来越漂亮了,对吧?
步骤4:拆分“偶数”和“奇数”字符
现在和我一起思考。i % 2什么时候等于0,什么时候是1?当0是偶数时是1,当i是奇数时是1。所以,在表达式int(number[i]) * (1 + i%2)中,当i是偶数时,就会有int(number[i]),而当i是奇数时,就会有int(number[i]) * 2。假设number是314159,则“偶数字符”(偶数位置的字符) 345按原样返回,“奇数字符”119乘以2。
此外,表达式a if a <= 9 else int(str(a)[0]) + int(str(a)[1])对于偶数字符来说也是微不足道的:因为它们是按-原样返回的,所以它们显然满足a <= 9,然后它们也按-原样返回。
注意到通过切片可以获得奇数字符:
s = 314159
even = s[::2] # 345
odd = s[1::2] # 119所以我们可以把我们的功能分成两部分。现在它变大了,但之后它会变得更好:
def luhn(number):
evens = number[::2]
even_sum = sum(map(int, evens)) # sum even characters
odds = number[1::2]
odd_sum = sum(
a if a <= 9 else int(str(a)[0]) + int(str(a)[1])
for a in (int(odd) * 2 for odd in odds)
) # sum odd characters
return (
10 - (even_sum + odd_sum) % 10
)步骤5:更多的重构
在"a if a <= 9 else int(str(a)[0]) + int(str(a)[1])“中,这段代码的意思是:a的数字之和。因为,如果a只有一个数字(a <= 9),我们只是返回它;否则,我们将其第一个和第二个数字相加。
但是,再仔细看一看,我们将str(int(odd) * 2) for odd in odds生成的所有数字的数字之和相加!这意味着我们可以先将所有数字连在一起,然后把它们全部加起来:
def luhn(number):
evens = number[::2]
even_sum = sum(map(int, evens)) # sums even characters
odds = number[1::2]
multiplied_by_two = (str(int(odd) * 2) for odd in odds)
all_digits = ''.join(multiplied_by_two)
odd_sum = sum(map(int, all_digits))
return (
10 - (even_sum + odd_sum) % 10
)最后,我们把这两个总和合并为一个:
def luhn(number):
evens = number[::2]
odds = number[1::2]
multiplied_by_two = (str(int(odd) * 2) for odd in odds)
all_digits = ''.join(multiplied_by_two)
total_sum = sum(map(int, evens + all_digits))
return (
10 - total_sum % 10
)现在我们只是缩成一个表达式:
def luhn(number):
return (
10 - sum(
map(
int,
number[::2] + ''.join(
str(int(odd) * 2) for odd in number[1::2]
)
)
) % 10
)最后,我们让它成为一条直线,并完成您的程序:
ID = input("Enter your first 8 digits of your id : ")
print(10 - sum(map(int, ID[::2] + ''.join(str(int(odd) * 2) for odd in ID[1::2]))) % 10)一些指标
通过比较我们的解决方案:
import timeit
ID = '12345678'
print(timeit.timeit(lambda: 10 - sum(map(lambda a: a if a <= 9 else int(str(a)[0]) + int(str(a)[1]), [int(ID[i]) if i % 2
== 0 else int(ID[i]) * 2 for i in range(8)])) % 10, number=1000000))
print(timeit.timeit(lambda: 10 - sum(map(int, ID[::2] + ''.join(str(int(odd) * 2) for odd in ID[1::2]))) % 10, number=1000000))你可以看到后者的速度快了30%。
https://stackoverflow.com/questions/67542033
复制相似问题