背景
在我总结的代码段中,有这样一段代码段。
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算法的步骤如下:
- 从右到左遍历数字序列: 从号码的最后一位开始,依次向左遍历每一位数字。
- 对偶数位数字进行加倍: 如果数字的位置是从右数的偶数位置(即第2、4、6...位),就将该数字加倍。如果加倍后的结果大于9,则将结果的各位数字相加(例如,18会变为1 + 8 = 9)。
- 将加倍后的数字与其他未加倍的数字相加: 将所有未加倍的数字和经过加倍处理后的数字相加。
- 检查总和是否为10的倍数: 最终的总和如果是10的倍数(即总和 % 10 == 0),则该号码是有效的;否则,该号码无效。
示例
假设要验证一个信用卡号码 4539 1488 0343 6467
。
-
从右到左遍历,并对偶数位数字加倍:
7
(偶数位,未加倍)6
(偶数位,加倍为12
,然后将1 + 2 = 3
)4
(偶数位,未加倍)3
(偶数位,加倍为6
)6
(偶数位,未加倍)0
(偶数位,加倍为0
)8
(偶数位,未加倍)8
(偶数位,加倍为16
,然后将1 + 6 = 7
)- 依此类推。
-
计算所有数字的总和: 偶数位加倍后的数字和未加倍数字相加后,得到一个总和。
-
检查总和是否为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 这是一个有效的号码
又学到了一个新的算法,可以的。
想要查看这个示例的可以前往这里,如果觉得本文有用,感谢点赞收藏。