Perl Weekly Challenge 279.

My solutions (task 1 and task 2 ) to the The Weekly Challenge - 279.

Task 1: Sort Letters

Submitted by: Mohammad Sajid Anwar
You are given two arrays, @letters and @weights.

Write a script to sort the given array @letters based on the @weights.

Example 1
Input: @letters = ('R', 'E', 'P', 'L')
       @weights = (3, 2, 1, 4)
Output: PERL
Example 2
Input: @letters = ('A', 'U', 'R', 'K')
       @weights = (2, 4, 1, 3)
Output: RAKU
Example 3
Input: @letters = ('O', 'H', 'Y', 'N', 'P', 'T')
       @weights = (5, 4, 2, 6, 1, 3)
Output: PYTHON

I assume the inputs are a string of characters and a string with space separated numbers (they could be more than one digit long). I split both arguments, use zip from List::Utils to make a Schwartzian transform for sorting, i.e., I make arrays of the form [string, number], sort according to number and extract string. The result fits a 1.5liner.

perl -Mexperimental=for_list -MList::Util=zip -E '
for my($l,$n)(@ARGV){say "Letters: $l, numbers: $n -> ", join "", map {$_->[0]}
sort {$a->[1] <=> $b->[1]} zip [split "", $l], [split " ", $n]}
' REPL "3 2 1 4" AURK "2 4 1 3" OHYNPT "5 4 2 6 1 3"

Results:

Letters: REPL, numbers: 3 2 1 4 -> PERL
Letters: AURK, numbers: 2 4 1 3 -> RAKU
Letters: OHYNPT, numbers: 5 4 2 6 1 3 -> PYTHON

The full code is similar but checks for special situations.

 1  # Perl weekly challenge 279
 2  # Task 1:  Sort Letters
 3  #
 4  # See https://wlmb.github.io/2024/07/22/PWC279/#task-1-sort-letters
 5  use v5.36;
 6  use experimental qw(for_list);
 7  use List::Util qw(zip);
 8  die <<~"FIN" unless @ARGV && @ARGV%2==0;
 9      Usage: $0 S1 N1 S2 N2...
10      to sort the characters of string Si according to the space-separated numbers Ni.
11      FIN
12  PAIRS:
13  for my($chars, $numbers)(@ARGV){
14      my @chars = split "", $chars;
15      my @numbers = split " ", $numbers;
16      warn("Expected one number per char: chars: @chars, numbers: @numbers"), next PAIR
17          unless @chars == @numbers;
18      for(@numbers){warn("Only digits allowed: $_"), next PAIR unless /^[\d\s]+$/;}
19      my @schwartz=zip \@chars, \@numbers;
20      my $out = join "", map {$_->[0]} sort {$a->[1] <=> $b->[1] || $a->[0] cmp $b->[0]}
21                @schwartz;
22      say "chars: $chars, numbers: $numbers -> $out";
23  }
24  

Example:

./ch-1.pl REPL "3 2 1 4" AURK "2 4 1 3" OHYNPT "5 4 2 6 1 3"

Results:

chars: REPL, numbers: 3 2 1 4 -> PERL
chars: AURK, numbers: 2 4 1 3 -> RAKU
chars: OHYNPT, numbers: 5 4 2 6 1 3 -> PYTHON

Task 2: Split String

Submitted by: Mohammad Sajid Anwar
You are given a string, $str.

Write a script to split the given string into two containing exactly same number
of vowels and return true if you can otherwise false.

Example 1
Input: $str = "perl"
Ouput: false
Example 2
Input: $str = "book"
Ouput: true

Two possible strings "bo" and "ok" containing exactly one vowel each.
Example 3
Input: $str = "good morning"
Ouput: true

Two possible strings "good " and "morning" containing two vowels each or "good m"
and "orning" containing two vowels each.

The result is true whenever the number of vowels is even. These would include the extreme cases of no vowels or no letters. I can use tr to count vowels, yielding a half-liner.

perl -E 'say "$_ -> ", tr/aeiou//%2==0?"True":"False" for @ARGV' perl book "good morning"

Results:

perl -> False
book -> True
good morning -> True

The full code is similar:

 1  # Perl weekly challenge 279
 2  # Task 2:  Split String
 3  #
 4  # See https://wlmb.github.io/2024/07/22/PWC279/#task-2-split-string
 5  use v5.36;
 6  die <<~"FIN" unless @ARGV;
 7      Usage: $0 S1 S2...
 8      to check if string Si may be split into strings with the same
 9      number of vowels each.
10      FIN
11  say "$_ -> ", tr/aeiou//%2==0?"True":"False" for(@ARGV)
12  

Example:

./ch-2.pl perl book "good morning"

Results:

perl -> False
book -> True
good morning -> True
Written on July 22, 2024