学到了学到了,一个小小的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 这是一个有效的号码

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

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

相关推荐
勤劳打代码12 小时前
码力全开——导入 deepseek 模型到 IDE
mcp·trae
冯志浩20 小时前
Trae + SwiftUI 1 小时实现一个单词本 Mac App
trae
汪子熙1 天前
利用 Trae 开发平面直角坐标系的教学动画
人工智能·trae
027西瓜皮2 天前
使用 Leaflet.js 生成北京地铁地图(Trae实现)
前端·trae
VioletJack2 天前
使用 AI IDE 不写任何代码做一个博客网站
前端·cursor·trae
用户21411832636022 天前
dify案例分享-基于database插件实现Text2sql的数据库查询图表工作流
trae
汪子熙2 天前
使用 Trae 开发一个演示勾股定理的动画演示
前端·人工智能·trae
小old弟3 天前
🤔不会搭建技术博客,Trae+vitepress,😎3s搞定
前端·trae
创码小奇客3 天前
Java 对象变形记:BeanUtils 与 MapStruct 的高阶魔法实战
java·spring boot·trae