【问题标题】:Calculating Luhn Algorithm with Java 8 Stream使用 Java 8 流计算 Luhn 算法
【发布时间】:2015-11-08 08:42:43
【问题描述】:

我正在尝试借助 Java 8 中的 Stream API 验证 IMEI 号码。

private void ValidateIMEI() {
    field //a field holding an IMEI Number
            .getText().chars()
            .map(this::ConvertASCIIToNumer);
}

我被卡住的部分是将偶数加倍并除以 10。

最初,我尝试了传统的 for 循环:

private void ValidateIMEI() {
    int[] numbers = field //a field holding an IMEI Number
            .getText().chars()
            .map(this::ConvertASCIIToNumer).toArray();

    int sum = 0;
    for (int i = 0; i < numbers.length; i++) {
        //Double the even number and divide it by 10. add quotient and remainder
        if ((numbers[i]+1) % 2 == 0) {
            numbers[i] = numbers[i] * 2;
            numbers[i] = numbers[i] / 10 + numbers[i] % 10;
        }
        sum += numbers[i];
    }

    if (sum%10==0) {
        status.setText("Valid");
    }
    else{
        status.setText("InValid");
    }        
}

但是代码被破坏了,特别是使用了我不想要的 For 循环。

那么,任何人都可以帮助在 Java 8 中仅使用 Stream API 实现 Luhn algorithm 吗?

ConvertASCIIToNumer 的代码:

private int ConvertASCIIToNumer(int value) {
    return Character.digit(value, 10);
}

【问题讨论】:

    标签: java algorithm java-8 java-stream


    【解决方案1】:

    您的错误是当您应该将具有偶数索引的数字加倍时,您将偶数加倍。由于该算法中的索引很重要,我建议使用索引的IntStream

    boolean isValid =
        IntStream.range(0,numbers.length)
                 .map (i -> (((i%2) ^ (numbers.length%2)) == 0) ? ((2*numbers[i])/10+(2*numbers[i])%10) : numbers[i])
                 .sum() % 10 == 0;
    

    编辑:我只是改变了条件,因为数组的长度决定了奇数或偶数索引是否应该乘以 2。

    如果数组的长度是偶数,偶数索引中的数字应该加倍:

    Index 0 1 2 3 4 5
    
    Digit 1 5 2 5 2 6
          -   -   -
    

    如果数组的长度是奇数,奇数索引中的数字应该是双倍:

    Index 0 1 2 3 4
    
    Digit 1 5 2 5 2
            -   -
    

    【讨论】:

    • woha int 无法转换为布尔值
    • 我会将 a^b == 0 替换为 a == b
    • 或者,您可以只迭代到 numbers 数组长度的一半,并在每次迭代中处理一对数字。
    • @RiaD 或(i-numbers.length()) % 2 == 0。 (我知道,这对于负 is 和非常长的数组会溢出,但我们碰巧知道在我们的例子中这些都不是真的。)
    【解决方案2】:

    这是我能做到的最漂亮的:

    String num; // your IMEI number
    int[] a = {num.length() % 2 == 0 ? 1 : 2};        // 1 if length even, 2 otherwise
    boolean isLuhn = num.chars()
            .map(i -> i - '0')         // convert to the int equivalent
            .map(n -> n * (a[0] = a[0] == 1 ? 2 : 1)) // multiply by 1, 2 alternating
            .map(n -> n > 9 ? n - 9 : n)              // handle sum of digits
            .sum() % 10 == 0;                         // mod 10 should be zero
    

    这里使用的“技巧”是使用int[],而不是int,变量来保存乘数。这是只允许引用“有效最终”变量的解决方法; array 引用实际上是最终的,但它的 contents(只有一个元素)不一定是!

    【讨论】:

    • 当你真正想要chars 时,你不需要拆分成字符串。换句话说,不要使用Arrays.stream(num.split(""))。您只需要num.chars().map(c -&gt; c - '0')...
    • @Holger omg ... 一直以来我从未注意到这种方法。谢谢你的课:)
    • 第一个.map() 中的i 与上面定义的变量int[] i 冲突。我收到此错误:Lambda expression's parameter i cannot redeclare another local variable defined in an enclosing scope.
    • @maxxyme 啊。我现在修好了。 (我通常没有方便的编译器,因为我的大部分代码都是在手机上翻阅的)
    猜你喜欢
    • 1970-01-01
    • 2014-02-10
    • 2021-05-16
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 2014-12-25
    • 1970-01-01
    相关资源
    最近更新 更多