Perl Weekly Challenge 224: Special Notes

These are some answers to the Week 224, Task 1, of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few days from now (on July 9, 2023, at 23:59). This blog post offers some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 1: Special Notes

You are given two strings, $source and $target.

Write a script to find out if using the characters (only once) from source, a target string can be created.

Example 1

Input: $source = "abc"
       $target = "xyz"
Output: false

Example 2

Input: $source = "scriptinglanguage"
       $target = "perl"
Output: true

Example 3

Input: $source = "aabbcc"
       $target = "abc"
Output: true

This task is somewhat similar to the "Good String" task of week 221, and we'll use essentially the same methods.

Special Notes in Raku

We can store the input source characters in a Bag and use the ⊆ subset of or equal to operator, infix_%E2%8A%86) to figure out whether all letters of a word can be found in the input string. In this context, bags are clever enough to manage duplicates in the input characters and use input characters only once.

sub special-note ($source, $target) {
    my $chars = $source.comb.Bag;
    return $target.comb.Bag ⊆ $chars;
}

for ("abc", "xyz"), ("scriptinglanguage", "perl"), 
        ("aabbcc", "abc") -> @test {
    printf "%-20s - %-7s => ", "@test[0]", "@test[1]";
    say special-note  @test[0], @test[1];
}

This program displays the following output:

$ raku ./main.raku
abc                  - xyz     => False
scriptinglanguage    - perl    => True
aabbcc               - abc     => True

Special Notes in Perl

Perl doesn't have Bags and set operators, but we can use a hash as a letter histogram to the same effect, with a loop to check whether each letter of $target word can be found in $source string.

use strict;
use warnings;
use feature 'say';

sub special_note {
    my ($source, $target) = @_;
    my %chars;
    $chars{$_}++ for split //, $source;
    for my $let (split //, $target) {
        return "false" unless $chars{$let};
        $chars{$let}--;
    }
    return "true";
}
for my $test ([ "abc", "xyz"], 
    ["scriptinglanguage", "perl"],  ["aabbcc", "abc"] ) {
    printf "%-20s - %-7s => ", "@$test[0]", "@$test[1]";
    say special_note @$test[0], @$test[1];
}

_

This program displays the following output:

$ perl ./special-note.pl
abc                  - xyz     => false
scriptinglanguage    - perl    => true
aabbcc               - abc     => true

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on July 16, 2023. And, please, also spread the word about the Perl Weekly Challenge if you can.

Leave a comment

About laurent_r

user-pic I am the author of the "Think Perl 6" book (O'Reilly, 2017) and I blog about the Perl 5 and Raku programming languages.