学到了学到了,一个小小的demo里隐藏着一个有趣的算法

背景

在我总结的代码段中,有这样一段代码段。

js 复制代码
const digitize = n => [...`${Math.abs(n)}`].map(i => parseInt(i));

这段代码的作用很简单,那就是将给定的数字转成数字数组,并且会去掉符号,然后再转成数字数组。

我们来看一些简单的使用示例。

js 复制代码
digitize(-123); // [1,2,3]
digitize(123); // [1,2,3] 

当然这段代码也还存在问题,那就是并没有对小数做处理。例如:

js 复制代码
digitize(12.3); // [1,2,NaN,3]

要改造起来也很简单,有2种方式,第一是在n中作处理,比如利用Math.ceil,Match.floor,Math.round方法来将n转换一遍。即:

js 复制代码
const digitize = n => [...`${Math.abs(Math.floor(n))}`].map(i => parseInt(i));

第二种就是在最后的结果中过滤一下。如下:

js 复制代码
const digitize = n => [...`${Math.abs(n)}`].map(i => parseInt(i)).filter(i => !isNaN(i));

当然,这不是本文的重点,接下来,我让trae帮我实现一个demo实战示例,如下所示:

随后trae帮我实现了一个如下图所示的示例:

这让我很好奇这里面的实现,结果竟让我发现了一个有趣的算法,这个算法叫做Luhn算法。那么重点来了,什么是Luhn算法?

我表示并不知道这个算法,孤陋寡闻了,接下来,让我们一起来了解一下这个算法吧。

luhn算法

定义

Luhn 算法(又称模10算法)是一种用于验证各种标识符(如信用卡号、社会保障号码、IMEI 号码等)是否有效的简单校验算法。它通过对数字序列进行一定的数学运算,生成一个校验位,从而检查号码的有效性。Luhn 算法的主要目的是检测输入号码是否符合预定的规则,防止常见的输入错误。

算法步骤

Luhn算法的步骤如下:

  1. 从右到左遍历数字序列: 从号码的最后一位开始,依次向左遍历每一位数字。
  2. 对偶数位数字进行加倍: 如果数字的位置是从右数的偶数位置(即第2、4、6...位),就将该数字加倍。如果加倍后的结果大于9,则将结果的各位数字相加(例如,18会变为1 + 8 = 9)。
  3. 将加倍后的数字与其他未加倍的数字相加: 将所有未加倍的数字和经过加倍处理后的数字相加。
  4. 检查总和是否为10的倍数: 最终的总和如果是10的倍数(即总和 % 10 == 0),则该号码是有效的;否则,该号码无效。

示例

假设要验证一个信用卡号码 4539 1488 0343 6467

  1. 从右到左遍历,并对偶数位数字加倍:

    • 7 (偶数位,未加倍)
    • 6 (偶数位,加倍为 12,然后将 1 + 2 = 3)
    • 4 (偶数位,未加倍)
    • 3 (偶数位,加倍为 6)
    • 6 (偶数位,未加倍)
    • 0 (偶数位,加倍为 0)
    • 8 (偶数位,未加倍)
    • 8 (偶数位,加倍为 16,然后将 1 + 6 = 7)
    • 依此类推。
  2. 计算所有数字的总和: 偶数位加倍后的数字和未加倍数字相加后,得到一个总和。

  3. 检查总和是否为10的倍数: 如果总和是10的倍数,则该号码是有效的。

通过这种方式,Luhn算法能够检测号码中的常见输入错误,如一个数字的错误或两个数字的交换。

算法应用

Luhn 算法广泛应用于:

  • 信用卡验证:用来确保输入的信用卡号符合格式规范。
  • 社会保障号码验证:检查社会保障号码是否有效。
  • IMEI号码验证:用于验证手机设备的 IMEI 编号。

算法实现

了解了这个算法之后,接下来,让我们来看看这个算法的实现。

首先根据算法描述,第一步我们需要从右往左开始遍历每一位数字,因此我们可以将给定的数字进行反转,注意我们可以将数字转成数字数组,然后再进行反转。

接着第二步,我们需要依次遍历数字数组中的每一个数,然后根据位置来判断是否为偶数(即循环索引值)。如果是偶数,则我们需要将该数加倍,然后判断是否大于9,如果大于9,则将结果的个位数字相加。但实际上这一步,我们可以换个思路想,如果结果大于9,实际上我们就可以将结果减去9即可以得到结果的个位数字相加后的结果。

例如18大于9,将结果相加即1 + 8 = 9,实际上也等价于18 - 9 = 9。

然后求出加倍数字与未加倍数字之和后,判断是否是10的倍数即可。

根据这个分析,我们就可以写出这个算法的实现。如下:

js 复制代码
// 注意digits是数字数组,也就是经过digitize方法处理后结果
const validateCardWithLuhn = (digits) => {
    // 先对数字进行反转
    const reDigits = [...digits].reverse();
    
    let sum = 0; // 计算求和结果
    
    reDigits.forEach((digit, index) => {
        // 判断是否是偶数位置
        if(index % 2 === 1){
            // 如果是偶数位,则加倍
            digit *= 2;
            // 如果加倍结果大于9,则减去9,相当于将结果的个位数字相加后的结果
            if(digit > 9){
                digit -= 9;
            }
        }
        
        sum += digit; // 将结果相加
    })
    
    return sum % 10 === 0; // 然后比较是否是10的倍数
}

当然也可以使用for循环来替代forEach实现,都是可以的,让我们试试结果。如下所示:

js 复制代码
validateCardWithLuhn(digitize(4539148803436467)); // true 这是一个有效的号码

又学到了一个新的算法,可以的。

想要查看这个示例的可以前往这里,如果觉得本文有用,感谢点赞收藏。

相关推荐
Molesidy7 小时前
【VSCode】VSCode或者Trae的扩展文件夹以及用户设置文件夹的路径更改到指定位置
ide·编辑器·trae
yosh'joy!!10 小时前
下载Trae使用
ai·trae
豆包MarsCode1 天前
只需一个指令,让 OpenClaw 安排 TRAE 干活
trae
sugar15691 天前
Trae快速构建自己项目的docker镜像
docker·容器·trae
sugar15691 天前
Trae 添加项目规则,快速完成crmeb项目本地开发环境搭建
docker·容器·trae
欧简墨2 天前
kotlin Android Extensions插件迁移到viewbinding总结
android·trae
arbboter2 天前
【AI编程】约束即设计:AI时代的人机边界重构
ai编程·ai工作流·人机协作·trae·声明式执行·流程编排
进击的雷神4 天前
Trae AI IDE 完全指南:从入门到精通
大数据·ide·人工智能·trae
圣殿骑士-Khtangc5 天前
Trae IDE AI 编程超全使用教程|从入门到精通,解锁 AI 开发新效率
ide·人工智能·ai编程·编程助手·trae
Mr_Carl7 天前
我用 Trae 花了一周,从零打造了一个 AI 面试官🚀
面试·trae·vibecoding