首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Luhn算法id数

Luhn算法id数
EN

Stack Overflow用户
提问于 2021-05-14 23:33:25
回答 1查看 264关注 0票数 0

我正在使用Luhn算法来查找I检查号。例如-输入- 12345678,输出- 2。我试图以最有效的方式,以及在最少的行可能。到目前为止,我写了这个:

代码语言:javascript
复制
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字符串转换不满意。但我在寻求任何改善。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-15 02:15:38

欢迎来到StackOverflow!

超短,但有依赖性

如果您可以依赖外部依赖项,请查看luhn package。您可以使用pip install luhn安装它,然后您的程序变成:

代码语言:javascript
复制
from luhn import generate

ID = input("Enter your first 8 digits of your id : ")
print(generate(ID))

再干净不过了。

更改您的代码

但假设您不想使用第三方包。让我们首先将您的代码放在一个函数中,并将其格式化:

代码语言:javascript
复制
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替换您的列表理解,以使它更快一些,因为您不需要首先构建整个列表:

代码语言:javascript
复制
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读起来要好得多。

将其应用于以前的功能:

代码语言:javascript
复制
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)。因此,我们的职能是:

代码语言:javascript
复制
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。假设number314159,则“偶数字符”(偶数位置的字符) 345按原样返回,“奇数字符”119乘以2

此外,表达式a if a <= 9 else int(str(a)[0]) + int(str(a)[1])对于偶数字符来说也是微不足道的:因为它们是按-原样返回的,所以它们显然满足a <= 9,然后它们也按-原样返回。

注意到通过切片可以获得奇数字符:

代码语言:javascript
复制
s = 314159
even = s[::2] # 345
odd = s[1::2] # 119

所以我们可以把我们的功能分成两部分。现在它变大了,但之后它会变得更好:

代码语言:javascript
复制
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生成的所有数字的数字之和相加!这意味着我们可以先将所有数字连在一起,然后把它们全部加起来:

代码语言:javascript
复制
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
    )

最后,我们把这两个总和合并为一个:

代码语言:javascript
复制
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
    )

现在我们只是缩成一个表达式:

代码语言:javascript
复制
def luhn(number):
    return (
        10 - sum(
            map(
                int,
                number[::2] + ''.join(
                    str(int(odd) * 2) for odd in number[1::2]
                )
            )
        ) % 10
    )

最后,我们让它成为一条直线,并完成您的程序:

代码语言:javascript
复制
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)

一些指标

通过比较我们的解决方案:

代码语言:javascript
复制
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%。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67542033

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档