The Weekly Challenge - 398

TASK #2: String Difference
You are given an array of equal length strings.
Write a script to find the difference integer array of each word in the
given array. There will be one word with a different array; return that word.

Each words[i] can be converted into a difference integer array
difference[i] of length n - 1 where difference[i][j] = words[i][j+1] - words[i][j]

Rewrite:
Let's rewrite this task to make it easier to understand:

1. You are given an array of strings. All strings have the same length.
2. Each string can be converted into an array of integers by calculating the
difference between the alphabetical positions of every two consecutive(!) letters.
For example, the letter a has position 0, b has position 1, c has position 2,
and so on.
3. The difference between two consecutive (!) letters is calculated as:
position of next letter - position of current letter
Example:
"ab" => [1 - 0] = [1]
"bc" => [2 - 1] = [1]
4. The task is to find the one string whose difference array is different
from all the others. Exactly one string has a difference array that
differs from the difference array shared by all the other strings.
Return that string.

Notes:
a. The function that can solve the task: substr
Example: substr($word, $i, 2), which extracts 2 characters from $word,
starting at position $i.
- my $word = "cba";
- $i = 0 -> cb
- $i = 1 -> ba
b. 'ord' converts a character into its numerical character code. For lowercase
English letters, the differences calculated with 'ord' are exactly the same
as those calculated using alphabet positions (a = 0, b = 1, etc.).
c. Exactly one string has a difference array: filter with grep,
e.g. grep { $count{$_} == 1 } @result;

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

sub string_difference {

    my @words = @_;
    my @result;

    for my $word (@words) {

        my @differences;

        for my $i (0 .. length($word) - 2) {

            my $first  = ord(substr($word, $i, 1));
            my $second = ord(substr($word, $i + 1, 1));

            push @differences, $second - $first;
        }
        
        # Convert the complete difference array into a string.
        # join(',', ...) separates the values with commas.
        # For example: [2, 2, 2] becomes "2,2,2".
        #        
        # This is important: we want to compare complete difference
        # sequences, not individual differences.
        push @result, join(',', @differences);
    }

    # Count how often each complete difference sequence occurs.
    # The hash key is the difference sequence;
    # the hash value is its number of occurrences.
    my %count;
    $count{$_}++ for @result;

    # Find the index of the difference sequence that occurs only once.
    #
    # grep returns a list. Since exactly one sequence is unique,
    # we assign that single index to $index.
    my ($index) = grep { $count{$result[$_]} == 1 } 0 .. $#result;

    return $words[$index];
}

#  Tests

my @words;

# Example 1
@words = ("ab", "bc", "cd", "zy");
print "Result ex. 1: ", string_difference(@words), "\n"; # Output: "zy"

# Example 2
@words = ("cba", "fed", "azy");
print "Result ex. 2: ", string_difference(@words), "\n"; # Output: "azy"

# Example 3
@words = ("pop", "ada", "beb", "cfc");
print "Result ex. 3: ", string_difference(@words), "\n"; # Output: "pop"

# Example 4
@words = ("aaaa", "zzzz", "mmmm", "aaba");
print "Result ex. 4: ", string_difference(@words), "\n"; # Output: "aaba"

# Example 5
@words = ("aceg", "bdfh", "cegi", "azbz");
print "Result ex. 5: ", string_difference(@words), "\n"; # Output: "azbz"

# Example 6
@words = ("acegik", "bdfhjl", "cegikm", "azbycx"); 
print "Result ex. 6: ", string_difference(@words), "\n"; # Output: "azbycx"

# Example 7
@words = ("acegikm", "bdfhjln", "cegikmo", "azbycxd"); 
print "Result ex. 7: ", string_difference(@words), "\n"; # Output: "azbycxd"

# Example 8
@words = ("acegikmo", "bdfhjlnp", "cegikmoq", "azbycxdw"); 
print "Result ex. 8: ", string_difference(@words), "\n"; # Output: "azbycxdw"

# Example 9
@words = ("abd", "abd", "abd", "acd");
print "Result ex. 9: ", string_difference(@words), "\n"; # Output: "acd"