### Perl Weekly Challenge: Week 264

#### Challenge 1:

Greatest English Letter

You are given a string, `\$str`, made up of only alphabetic characters `[a..zA..Z]`.

Write a script to return the greatest english letter in the given string.

A letter is greatest if it occurs as lower and upper case. Also letter ‘b’ is greater than ‘a’ if ‘b’ appears after ‘a’ in the English alphabet.

##### Example 1
``````Input: \$str = 'PeRlwEeKLy'
Output: L

There are two letters E and L that appears as lower and upper.
The letter L appears after E, so the L is the greatest english letter.
``````
##### Example 2
``````Input: \$str = 'ChaLlenge'
Output: L
``````
##### Example 3
``````Input: \$str = 'The'
Output: ''
``````

No one-liners this week but the Raku solution is still pretty concise.

We start by taking the input and splitting it into individual characters with `.comb()`. Then we use `.classify()` as we did last week to put the upper and lower case characters into separate keys ('upper' and 'lower') of a hash called `%chars`.

``````\$str.comb.classify({ \$_ ~~ 'A' .. 'Z' ?? 'upper' !! 'lower'}, :into(my %chars));
``````

Treating the values of `%chars<upper>` and `%chars<lower>` as `Set`s, the letters that they have in common will be the intersection of those sets. We can find the intersection with the `∩` operator but there is one additional step we must take first; The two sets must contain the same types of elements so we transform the elements of the lower case set to upper case with `.map()` and `.uc()`.

The intersection is also a `Set` so we need the `.keys()` method to extract its' elements (i.e. the letters). `.sort[*-1]` gives the he greatest (i.e. highest alphabetical value) letter. One last scenario to consider is if the intersection is empty which means there were no great letters in the string. `// q{''}` prints empty quotes if that is the case.

``````say (%chars<upper>.values ∩ %chars<lower>.values.map({ .uc })).keys.sort[*-1] // q{''};
``````

(Full code on Github.)

In Perl we don't have `.classify()` so we have to recreate it ourselves. First, I declared two hashes to hold the upper and lower case characters.

``````my %upper;
my %lower;
``````

Then after splitting the input into individual characters, for each character...

``````for my \$char (split //, \$str) {
``````

...If it is upper case, it is added as a key into the `%upper` hash with the arbitrary value of 1. The value doesn't matter, we just need the key to exist.

``````    if (\$char =~ /[[:upper:]]/) {
\$upper{\$char} = 1;
``````

If the character wasn't upper case, it is added to `%lower`.

``````    } else {
\$lower{\$char} = 1;
}
}
``````

A variable is reserved to hold the current greatest letter.

``````my \$greatest = undef;
``````

Then we iterate through the sorted keys of `%upper`.

``````for my \$char (sort keys %upper) {
``````

For each one, we convert it to lower case and see if a key with that value exists in `%lower`. The method I used to convert to lower case using `ord()` and `chr()` relies on the fact that the numeric values of lower case ASCII characters are exactly 32 (the numeric values of the space character) more than their upper-case counterparts. It is needlessly complicated and honestly I don't know what I was thinking. I could have just used `lc()`. In fact in hindsight I see I could have just had upper-case keys in `%lower`.

``````    if (exists \$lower{chr((ord \$char) + (ord ' '))}) {
``````

Anyway if the upper-case letter has a lower-case counterpart, it becomes the new current greatest letter. \$greatest = \$char; } }

Whatever is the `\$greatest` after we've gone through all the letters in `%upper` is the final answer and is printed out. If it was still `undef` that means we didn't find a greatest letter so empty quotes are printed.

``````say \$greatest // q{''};
``````

(Full code on Github.)

#### Challenge 2:

Target Array

You are given two arrays of integers, `@source` and `@indices`. The `@indices` can only contains integers `0 <= i < size of @source`.

Write a script to create target array by insert at index `\$indices[i]` the value `\$source[i]`.

##### Example 1
``````Input: @source  = (0, 1, 2, 3, 4)
@indices = (0, 1, 2, 2, 1)
Output: (0, 4, 1, 3, 2)

@source  @indices  @target
0        0         (0)
1        1         (0, 1)
2        2         (0, 1, 2)
3        2         (0, 1, 3, 2)
4        1         (0, 4, 1, 3, 2)
``````
##### Example 2
``````Input: @source  = (1, 2, 3, 4, 0)
@indices = (0, 1, 2, 3, 0)
Output: (0, 1, 2, 3, 4)

@source  @indices  @target
1        0         (1)
2        1         (1, 2)
3        2         (1, 2, 3)
4        3         (1, 2, 3, 4)
0        0         (0, 1, 2, 3, 4)
``````
##### Example 3
``````Input: @source  = (1)
@indices = (0)
Output: (1)
``````

This one was really easy because once we have imported the sources and indices from command-line parameters (they look like e.g. `"0 1 2 3 4" "0 1 2 2 1"` for example 1.)...

``````my @sources = \$s.split(/\s+/).map({ .Int });
my @indices = \$i.split(/\s+/).map({ .Int });
``````

...And declared a variable to hold the output...

``````my @output;
``````

...we can traverse through `@sources` by index and use it together with the equivalent index in `@indices` as parameters to `.splice()` which does all the work of inserting the number in the right place in `@output`.

``````for @sources.keys -> \$i {
@output.splice(@indices[\$i], 0,  @sources[\$i]);
}
``````

And then we print `@output` formatted in the style of the example output.

`````` say q{(}, @output.join(q{, }), q{)};
``````

(Full code on Github.)

The Perl version is almost exactly equivalent.

``````my @sources = split /\s+/, \$ARGV[0];
my @indices = split /\s+/, \$ARGV[1];
my @output;

for my \$i (keys @sources) {
splice @output, \$indices[\$i], 0, \$sources[\$i];
}

say q{(}, (join q{, }, @output), q{)};
``````

(Full code on Github.)