Perl Weekly Challenge 389.

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

Task 1: Reorder Notes

Submitted by: Reinier Maliepaard

You are given an array [composer, notes, permutation],
reconstruct the melody by using each permutation value as
the destination position of the corresponding note. Use no
explicit for, foreach, or while loops. Output each result as
COMPOSER => reordered notes.

ASSUMPTION: Input is valid; the notes array and permutation
array have identical lengths, and the permutation contains
each position from 1 to N exactly once.

Example 1
Input: $melody = ['Bach', [qw(C D E F# G A B)], [7, 1, 6, 2, 5, 3, 4]]
Output: BACH => D F# A B G E C

Note 1 (C)  moves to position 7.
Note 2 (D)  moves to position 1.
Note 3 (E)  moves to position 6.
Note 4 (F#) moves to position 2.
Note 5 (G)  moves to position 5.
Note 6 (A)  moves to position 3.
Note 7 (B)  moves to position 4.

Example 2
Input: $melody = ['Beethoven', [qw(C D F# G Ab)], [1, 3, 5, 2, 4]]
Output: BEETHOVEN => C G D Ab F#

Note 1 (C)  stays at position 1.
Note 2 (D)  moves to position 3.
Note 3 (F#) moves to position 5.
Note 4 (G)  moves to position 2.
Note 5 (Ab) moves to position 4.

Example 3
Input: $melody = [ 'Brahms',
                 [qw(C Db Eb F G Ab Bb C D)],
                 [9, 3, 7, 1, 8, 5, 2, 6, 4] ]
Output: BRAHMS => F Bb Db D Ab C Eb G C

Example 4
Input: $melody = [ 'Bruckner',
                 [qw(G F# Bb C D Eb F)],
                 [4, 7, 2, 6, 1, 5, 3] ]
Output: BRUCKNER => D Bb F G Eb C F#

Example 5
Input: $melody = ['Berg', [qw(C#)], [1]]
Output: BERG => C#

Instead of explicit loops I could use tail recursion. I use a recursive function to walk over @ARGV, three terms at a time, taking advantage of the old parameter style, and I make another recursive function to build the output array, one note at a time. The result fits a two-liner.

Examples:

perl -E '
sub f{($C,$N,$P,@R)=@_;say("$C -> ",join " ",g([],map{[split" "]}$N,$P)->@*),
f(@R)if$C;}sub g($C,$N,$P){$C->[pop @$P]=pop@$N,g($C,$N,$P)if @$N;$C}f(@ARGV);
' 'Bach' 'C D E F# G A B' '7 1 6 2 5 3 4' \
  'Beethoven' 'C D F# G Ab' '1 3 5 2 4' \
  'Brahms' 'C Db Eb F G Ab Bb C D' '9 3 7 1 8 5 2 6 4' \
  'Bruckner' 'G F# Bb C D Eb F' '4 7 2 6 1 5 3' \
  'Berg' 'C#' '1'

Results:

Bach ->  D F# A B G E C
Beethoven ->  C G D Ab F#
Brahms ->  F Bb Db D Ab C Eb G C
Bruckner ->  D Bb F G Eb C F#
Berg ->  C#

The full code is:

 1  # Perl weekly challenge 389
 2  # Task 1:  Reorder Notes
 3  #
 4  # See https://wlmb.github.io/2026/08/31/PWC389/#task-1-reorder-notes
 5  use v5.36;
 6  use feature qw(try);
 7  use List::Util qw(all);
 8  die <<~"FIN" unless @ARGV and @ARGV%3==0;
 9      Usage: $0 C0 N0 P0 C1 N1 P1...
10      to arrange the notes Ni of the composition by composer Ci
11      applying the permutation Pi
12      FIN
13  
14  sub walk{
15      my ($composer, $notes, $permutations, @rest) = @_;
16      if($composer){
17              try {
18                  my @notes = split " ", $notes;
19                  my @permutations = split " ", $permutations;
20                  die "Number of notes should equal number of permutations"
21                      unless @notes==@permutations;
22                  die "Index out of range" unless all {1<=$_<=@permutations} @permutations;
23                  say "$composer -> ",
24                      join " ",
25                      permute_notes([], [@notes], [@permutations])->@*;
26              }
27              catch($e){
28                  warn "${e}Composer=$composer, Notes=$notes, Permutation=$permutations";
29              }
30              walk(@rest);
31      }
32  }
33  
34  sub permute_notes($current, $notes, $permutations){
35      if(@$notes){
36          my $note=pop @$notes;
37          my $place=pop @$permutations;
38          die "Repeated destination: $place" if defined $current->[$place-1];
39          $current->[$place-1]=$note;
40          permute_notes($current, $notes, $permutations)
41      }
42      return $current;
43  }
44  
45  walk(@ARGV);

Examples:

./ch-1.pl  'Bach' 'C D E F# G A B' '7 1 6 2 5 3 4' \
            'Beethoven' 'C D F# G Ab' '1 3 5 2 4' \
            'Brahms' 'C Db Eb F G Ab Bb C D' '9 3 7 1 8 5 2 6 4' \
            'Bruckner' 'G F# Bb C D Eb F' '4 7 2 6 1 5 3' \
            'Berg' 'C#' '1'

Results:

Bach -> D F# A B G E C
Beethoven -> C G D Ab F#
Brahms -> F Bb Db D Ab C Eb G C
Bruckner -> D Bb F G Eb C F#
Berg -> C#

Examples with errors:

./ch-1.pl 2>&1 'Bach' 'C D E F# G A B' '1 6 2 5 3 4' \
            'Beethoven' 'C D F# G Ab' '1 1 5 2 4' \
            'Brahms' 'C Db Eb F G Ab Bb C D' '10 3 7 1 8 5 2 6 4' \
            'Bruckner' 'G F# Bb C D Eb F' '0 7 2 6 1 5 3' \

Results:

Number of notes should equal number of permutations at ./ch-1.pl line 21.
Composer=Bach, Notes=C D E F# G A B, Permutation=1 6 2 5 3 4 at ./ch-1.pl line 29.
Repeated destination: 1 at ./ch-1.pl line 39.
Composer=Beethoven, Notes=C D F# G Ab, Permutation=1 1 5 2 4 at ./ch-1.pl line 29.
Index out of range at ./ch-1.pl line 23.
Composer=Brahms, Notes=C Db Eb F G Ab Bb C D, Permutation=10 3 7 1 8 5 2 6 4 at ./ch-1.pl line 29.
Index out of range at ./ch-1.pl line 23.
Composer=Bruckner, Notes=G F# Bb C D Eb F, Permutation=0 7 2 6 1 5 3 at ./ch-1.pl line 29.

Task 2: ZigZag Subarray

Submitted by: Roger Bell_West
You are given an array of integers.

Write a script to find the length of the longest contiguous
subarray where the numbers alternate between strictly
increasing and strictly decreasing (a ZigZag pattern).

A sequence of numbers $A = [a0, a1, …, ak]$ with length $k
>= 1 is considered a ZigZag sequence if every adjacent pair
alternates direction:

a_0 < a_1 > a_2 < a_3 > ...
OR
a_0 > a_1 < a_2 > a_3 < ...

NOTE: A single element (length 1) or any two distinct
elements (length 2) are automatically valid ZigZag
sequences. Equal adjacent numbers (e.g., 5, 5) break the
pattern.

Example 1
Input: @nums = (9, 4, 2, 10, 7, 8, 8, 1, 9)
Output: 5

ZigZag subarray: (4, 2, 10, 7, 8)

Example 2
Input: @nums = (1, 7, 4, 9, 2, 5)
Output: 6

ZigZag subarray: (1, 7, 4, 9, 2, 5)

Example 3
Input: @nums = (1, 2, 3, 4, 5)
Output: 2

ZigZag subarray: (1, 2)

Example 4
Input: @nums = (4, 4, 4)
Output: 1

Example 5
Input: @nums = (10, 20, 15, 12, 18)
Output: 3

ZigZag subarray: (10, 20, 15)

I use the spaceship operator <=> to compare succesive terms in the array. I change sign to each second comparison result. A zigzag sequence corresponds to a sequence of 1’s or of -1’s. Thus I count all such sequences and chose the largest using the max function from List::Util. The result fits a 2.5-liner.

Examples:

perl -MList::Util=max -E '
for(@ARGV){($c,@r)=split" ";push(@s,$c<=>($d=shift @r)),$c=$d while(@r);$s[2*$_]*=-1
for 0..(@s-1)/2;my @r;while(@s){$c=1;$d=shift@s;++$c if$d;++$c,shift @s while$s[0]*$d==1;
push@r,$c;}say "$_ -> ", max @r}
' "9 4 2 10 7 8 8 1 9"  "1 7 4 9 2 5" "1 2 3 4 5" "4 4 4" "10 20 15 12 18"

Results:

9 4 2 10 7 8 8 1 9 -> 5
1 7 4 9 2 5 -> 6
1 2 3 4 5 -> 2
4 4 4 -> 1
10 20 15 12 18 -> 3

The full code is:

 1  # Perl weekly challenge 389
 2  # Task 2:  ZigZag Subarray
 3  #
 4  # See https://wlmb.github.io/2026/08/31/PWC389/#task-2-zigzag-subarray
 5  use v5.36;
 6  use List::Util qw(max);
 7  die <<~"FIN" unless @ARGV;
 8      Usage: $0 S0 S1...
 9      to find the longest zigzag subsequence of the space separated
10      sequence Si="N0 N1..." where Nj are numbers.
11      FIN
12  
13  for(@ARGV){
14      my ($current, @rest)=split" ";
15      my @signs;
16      while(@rest){
17          push(@signs, $current <=> (my $next = shift @rest));
18          $current = $next;
19      }
20      $signs[2*$_] *= -1 for 0..(@signs-1)/2;
21      my @lengths;
22      while(@signs){
23          my $count = 1;
24          my $first_sign = shift @signs;
25          ++$count if $first_sign;
26          ++$count, shift @signs while @signs && $signs[0]*$first_sign==1;
27          push @lengths, $count;
28      }
29      say "$_ -> ", max @lengths;
30  }

Example:

./ch-2.pl "9 4 2 10 7 8 8 1 9"  "1 7 4 9 2 5" "1 2 3 4 5" "4 4 4" "10 20 15 12 18"

Results:

9 4 2 10 7 8 8 1 9 -> 5
1 7 4 9 2 5 -> 6
1 2 3 4 5 -> 2
4 4 4 -> 1
10 20 15 12 18 -> 3

/;

Written on August 31, 2026