Perl Weekly Challenge: Week 280

Challenge 1:

Twice Appearance

You are given a string, $str, containing lowercase English letters only.

Write a script to print the first letter that appears twice.

Example 1
Input: $str = "acbddbca"
Output: "d"
Example 2
Input: $str = "abccd"
Output: "c"
Example 3
Input: $str = "abcdabbb"
Output: "a"

I was hoping to be able to dispose of this challenge in one line with a regular expression but I couldn't figure it out so I fell back to this simple but effective method instead.

First a hash is created to store each character that has been seen.

my %seen;

Then the input string is split into characters and for each character...

for ($str.comb) -> $c {

...if it has already been seen, it means this is the second time we are seeing it. We print it out and exit the loop (and the script.)

    if %seen{$c}:exists {
        say $c;
        last;

If not, we mark it as seen.

    } else {
        %seen{$c} = True;
    }
}

(Full code on Github.)

This is the Perl version. It is a straightforward translation from Raku.

my %seen;

for (split //, shift) {
    if (exists $seen{$_}) {
        say $_;
        last;
    } else {
        $seen{$_} = 1;
    }
}

(Full code on Github.)

Challenge 2:

Count Asterisks

You are given a string, $str, where every two consecutive vertical bars are grouped into a pair.

Write a script to return the number of asterisks, *, excluding any between each pair of vertical bars.

Example 1
Input: $str = "p|*e*rl|w**e|*ekly|"
Output: 2

The characters we are looking here are "p" and "w**e".
Example 2
Input: $str = "perl"
Output: 0
Example 3
Example 3
Input: $str = "th|ewe|e**|k|l***ych|alleng|e"
Output: 5

The characters we are looking here are "th", "e**", "l***ych" and "e".

This time we can achieve a one-liner. I will describe the Perl version first.

$_= shift; s/\|.+?\||[^*]//g; say y/*//;

(Full code on Github.)

We take the first command-line argument as input with shift() and assign it to $_. With a regular expression we remove everything inside two | characters or outside but not a *. All that will be left are some asterisks and the most concise way to count them is with the y/// (another name for tr///) operator. Or at the cost of one more character but perhaps the gain of some clarity, we could have used length().

In Raku as well we do the removal via regular expression. But this time, the number of asterisks remaining is ciunted with .chars().

@*ARGS[0].subst(/\|.+?\| | <-[*]>/, q{}, :g).chars.say

(Full code on Github.)