RabbitFarm

2024-10-14

Double Luhn

The examples used here are from the weekly challenge problem statement and demonstrate the working solution.

Part 1: Double Exist

You are given an array of integers, @ints. Write a script to find if there exist two indices $i and $j such that:

  1. $i≠$j
  2. 0 $i < size @ints and 0 $j < size @ints
  3. $ints[$i] = 2 $ints[$j]

The majority of the work can be done in a few lines. If there is a more elegant way to do this, it escaped me when I was writing this code!

nested loop to determine if the conditions hold 1 ⟩≡


sub double_exist{
my(@a) = @_;
do{
my $i = $_;
do{
my $j = $_;
if($i != $j){
return 1 if $a[$i] == 2 * $a[$j];
}
} for 0 .. @a - 1;
} for 0 .. @a - 1;
return 0;
}

Fragment referenced in 2.

The rest of the code just tests this function.

"ch-1.pl" 2


preamble 3
nested loop to determine if the conditions hold 1
main 4

preamble 3 ⟩≡


use v5.40;

Fragment referenced in 2, 7.

main 4 ⟩≡


MAIN:{
say double_exist 6, 2, 3, 3;
say double_exist 3, 1, 4, 13;
say double_exist 2, 1, 4, 2;
}

Fragment referenced in 2.

Sample Run
$ perl perl/ch-1.pl 
1 
0 
1
    

Part 2: Luhn’s Algorithm

You are given a string $str containing digits (and possibly other characters which can be ignored). The last digit is the payload; consider it separately. Counting from the right, double the value of the first, third, etc. of the remaining digits. For each value now greater than 9, sum its digits. The correct check digit is that which, added to the sum of all values, would bring the total mod 10 to zero. Return true if and only if the payload is equal to the correct check digit.

This can also be done in relatively few lines. There are no real special cases here.

loop and evaluate the check sum 5 ⟩≡


sub luhn{
my($digits) = @_;
my @digits = $digits =~ m/([0-9])/g;
my $sum = 0;
my $check = pop @digits;
{
my $x = pop @digits;
my $y = pop @digits;
if(defined $x && defined $y){
$sum += $y + sum_digits 2 * $x;
}
else{
$sum += sum_digits 2 * $x;
}
redo if @digits;
}
return 1 if 0 == ($sum + $check) % 10;
return 0;
}

Fragment referenced in 7.

For convenience we’ll put the summing of digits for numbers > 10 in a separate function.

sum digits for numbers > 10 6 ⟩≡


sub sum_digits{
my($x) = @_;
if($x >= 10){
my @a = split //, $x;
return $a[0] + $a[1];
}
return $x;
}

Fragment referenced in 7.

The rest of the code drives some tests.

"ch-2.pl" 7


preamble 3
sum digits for numbers > 10 6
loop and evaluate the check sum 5
main 8

main 8 ⟩≡


MAIN:{
say luhn q/17893729974/;
say luhn q/4137 8947 1175 5904/;
say luhn q/4137 8974 1175 5904/;
}

Fragment referenced in 7.

Sample Run
$ perl perl/ch-2.pl 
1 
1 
0
    

References

The Weekly Challenge 290
Generated Code

posted at: 01:19 by: Adam Russell | path: /perl | permanent link to this entry