Perl Weekly Challenge: Week 67

Challenge 1:

Number Combinations

You are given two integers $m and $n. Write a script print all possible combinations of $n numbers from the list 1 2 3 … $m.

Every combination should be sorted i.e. [2,3] is valid combination but [3,2] is not.

Example:
Input: $m = 5, $n = 2

Output: [ [1,2], [1,3], [1,4], [1,5], [2,3], [2,4], [2,5], [3,4], [3,5], [4,5] ]

In Raku we can do this as a one-liner:

say q{[ }, (1 .. $m).combinations($n).map({ q{[} ~ @_.join(q{,}) ~ q{]} }).join(q{, }), q{ ]};

(Full code on Github.)

If we just wanted the answer it would be even simpler but formatting it exactly as the spec has it requires a little extra code.

Perl is a little trickier because it doesn't have a .combinations() method like Raku does. Luckily I could reuse my clone from challenge 38. With that, the Perl version also becomes quite simple.

my @result = combinations([1 .. $m], $n);
say q{[ }, (join q{, }, map { q{[} . (join q{,}, @{$_}) . q{]} } @result), q{ ]};

(Full code on Github.)

Challenge 2:

Letter Phone

You are given a digit string $S. Write a script to print all possible letter combinations that the given digit string could represent.

1_,@2ABC3DEF
4GHI5JKL6MNO
7PQRS8TUV9WXYZ
0#

(I had way too much fun making that dialpad.)

Example:
Input: $S = '35'

Output: ["dj", "dk", "dl", "ej", "ek", "el", "fj", "fk", "fl"].

Once again let's start with Raku.

I made a hash mapping digits to arrays of possible values.

my %digits = 
    1   => < _ , @ >,
    2   => < a b c >,
    3   => < d e f >,
    4   => < g h i >,
    5   => < j k l >,
    6   => < m n o >,
    7   => < p q r s >,
    8   => < t u v >,
    9   => < w x y z >,
    0   => [ q{} ],
    '*' => [ q{ } ],
    '#' => [ q{} ],
;

As in the previous task, formatting the result just right makes the code a bit more complex but the core is simple. The input string is split into individual digits. Each digit is mapped to an array of values using %digits and then the cross-product hyper operator [X] is applied to the arrays to give all the combinations.

say q{[}, ([X] $S.comb.map({ %digits{$_} })).map({ q{"} ~ @_.join({}) ~ q{"} }).join(q{, }), q{]};

(Full code on Github.)

For the Perl version, I also begin by building a digit to values map.

my %digits = (
    1   => [ q{_}, q{,}, q{@} ],
    2   => [qw/ a b c /],
    3   => [qw/ d e f /],
    4   => [qw/ g h i /],
    5   => [qw/ j k l /],
    6   => [qw/ m n o /],
    7   => [qw/ p q r s /],
    8   => [qw/ t u v /],
    9   => [qw/ w x y z /],
    0   => [ q{} ],
    '*' => [ q{ } ],
    '#' => [ q{} ],
);

Perl doesn't have [X] like Raku but once again my replacement, most recently seen in challenge 65 comes to the rescue. It's use is a bit more convoluted than in Raku but it gets the job done.

my @letters = map { $digits{$_} } split //, $S;
my @result = @{ $letters[0] };

for my $i (1 .. (scalar @letters) - 1 ) {
    @result = X(\@result, $letters[$i]);
}

All that remains by this point is to print out the result in the format used in the spec.

say q{[}, (join q{, }, map { q{"} . (join q{}, @{$_}) . q{"} } @result), q{]};

(Full code on Github.)