The Weekly Challenge - 290

TASK #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, $j) < scalar @ints
3) $ints[$i] == 2 * $ints[$j]
4) and for efficiency I test also: $ints[$j] == 2 * $ints[$i])

#!/usr/bin/perl
use strict;
use warnings;

sub double_exist {
    my @ints = @_;

    # typical "old-school" double for loop through all possible pairs of indices (i, j)    
    for my $i (0 .. $#ints) {
        for my $j ($i + 1 .. $#ints) {
            # check if $ints[$i] is twice $ints[$j] or vice versa
            # not perlish, but I like parentheses, expressing a thought...
            return ("true") if ( ($ints[$i] == 2 * $ints[$j]) || ($ints[$j] == 2 * $ints[$i]) );
        }
    }

    return ("false");
}

# Tests
my @ints;

# Example 1
@ints = (6, 2, 3, 3);
print(double_exist(@ints), "\n"); # Output: true

# Example 2
@ints = (3, 1, 4, 13);
print(double_exist(@ints), "\n"); # Output: false

# Example 3
@ints = (2, 1, 4, 2);
print(double_exist(@ints), "\n"); # Output: true

# Example 4
@ints = (1, 2, 3);
print(double_exist(@ints), "\n"); # Output: true

TASK #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.
#!/usr/bin/perl
use strict;
use warnings;

sub luhn_algorithm {
  
    # \D matches any non-digit character, g ensures all matches are replaced
    $_[0] =~ s/\D//g;  
    
    # reversing the digits ensures that you always start processing 
    # from the rightmost digit, regardless of whether the 
    # total number of digits is odd or even.
    
    my @digits = reverse (split(//, $_[0]));

    my $sum = 0;

    # start at 1, skipping the payload value
    foreach my $i (1..$#digits) {
        my $digit = $digits[$i];

        # double every second digit depending on position
        if ($i % 2 == 1) {
            $digit *= 2;
            # if the result is greater than 9, add the digits of the result
            if ($digit > 9) {
                my @split_digits = split(//, $digit);
                $digit = $split_digits[0] + $split_digits[1];
            }
        }

        $sum += $digit;
    }

    # If the sum + $digits[0] (=payload) is divisible by 10, the number is valid
    ( ($sum += $digits[0]) % 10 == 0 ) ? return ("true") : return ("false");
}

# Tests

my $str;

# Example 1
$str = "17893729974";
print(luhn_algorithm($str), "\n"); # Output: true

# Example 2
$str = "4137 8947 1175 5904";
print(luhn_algorithm($str), "\n"); # Output: true

# Example 3
$str = "4137 8974 1175 5904";
print(luhn_algorithm($str), "\n"); # Output: false