<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Bob Lied</title>
    <description>The latest articles on Forem by Bob Lied (@boblied).</description>
    <link>https://forem.com/boblied</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F470960%2F3925166c-2844-4880-92af-2dfede66665b.jpeg</url>
      <title>Forem: Bob Lied</title>
      <link>https://forem.com/boblied</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/boblied"/>
    <language>en</language>
    <item>
      <title>PWC 371 Subset Equilibrium (Just nod if you can hear me)</title>
      <dc:creator>Bob Lied</dc:creator>
      <pubDate>Tue, 28 Apr 2026 13:02:35 +0000</pubDate>
      <link>https://forem.com/boblied/pwc-371-subset-equilibrium-just-nod-if-you-can-hear-me-14im</link>
      <guid>https://forem.com/boblied/pwc-371-subset-equilibrium-just-nod-if-you-can-hear-me-14im</guid>
      <description>&lt;p&gt;Another explosive weekly challenge. And by explosive I mean exponential complexity. Let's see what we've got. First I'll adjust the background music for equilibrium ... &lt;a href="https://www.youtube.com/watch?v=7f3EGjRxxNI&amp;amp;list=RD7f3EGjRxxNI&amp;amp;start_radio=1" rel="noopener noreferrer"&gt;Comfortably Numb&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Relax, I'll Need Some Information First
&lt;/h2&gt;

&lt;p&gt;You are given an array of numbers.  Write a script to find all subsets where the sum of elements equals the sum of their indices.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Example 1 Input: @nums = (2, 1, 4, 3)
#.          Output: (2, 1), (1, 4), (4, 3), (2, 3)
#   Subset 1: (2, 1) Values: 2 + 1 = 3 Positions: 1 + 2 = 3
#   Subset 2: (1, 4) Values: 1 + 4 = 5 Positions: 2 + 3 = 5
#   Subset 3: (4, 3) Values: 4 + 3 = 7 Positions: 3 + 4 = 7
#   Subset 4: (2, 3) Values: 2 + 3 = 5 Positions: 1 + 4 = 5
#
# Example 2 Input: @nums = (3, 0, 3, 0)
#           Output: (3, 0), (3, 0, 3)
#   Subset 1: (3, 0) Values: 3 + 0 = 3 Positions: 1 + 2 = 3
#   Subset 2: (3, 0, 3) Values: 3 + 0 + 3 = 6 Positions: 1 + 2 + 3 = 6
#
# Example 3 Input: @nums = (5, 1, 1, 1)
#           Output: (5, 1, 1)
#   Subset 1: (5, 1, 1) Values: 5 + 1 + 1 = 7 Positions: 1 + 2 + 4 = 7
#
# Example 4 Input: @nums = (3, -1, 4, 2)
#           Output: (3, 2), (3, -1, 4)
#   Subset 1: (3, 2) Values: 3 + 2 = 5 Positions: 1 + 4 = 5
#   Subset 2: (3, -1, 4) Values: 3 + (-1) + 4 = 6 Positions: 1 + 2 + 3 = 6
#
# Example 5 Input: @nums = (10, 20, 30, 40)
#           Output: ()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Just the Basic Facts, Can You Show Me Where It Hurts?
&lt;/h2&gt;

&lt;p&gt;Perusing the examples, I see that there are a couple of unstated requirements. From example 1, the improper subset (1,2,3,4) should work, but it's not in the given output, so apparently that should be excluded. And in example two, the subset (3) should work, but it's not in the output, so apparently subsets have to have at least two members.&lt;/p&gt;

&lt;p&gt;I don't see any way of doing this other than generating all possible subsets and checking if they work. My approach is going to be to number the positions, and generate all possible subsets of the positions. Extracting members from the given list will be done with a hash slice. There's going to be a little annoyance that the task numbers positions starting from 1, while Perl array indexing is based from 0. &lt;/p&gt;

&lt;p&gt;For a set of &lt;em&gt;n&lt;/em&gt; members, there are 2&lt;sup&gt;&lt;em&gt;n&lt;/em&gt;&lt;/sup&gt;-1 possible subsets. I know that a way to generate subsets is to count from 1 to 2&lt;sup&gt;&lt;em&gt;n&lt;/em&gt;&lt;/sup&gt;-1 and check which bits are 1s in the binary representation. I know how to generate all possible subsets, but do I want to? Because I also know that there are CPAN modules that do this, and I have &lt;a href="https://metacpan.org/pod/Algorithm::Combinatorics#subsets" rel="noopener noreferrer"&gt;&lt;code&gt;Algorithm::Combinatorics&lt;/code&gt;&lt;/a&gt; hanging around from previous problems, with its convenient &lt;code&gt;subsets&lt;/code&gt; function, so let's use that.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Do Believe It's Working, Good
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;sseq&lt;/span&gt;&lt;span class="err"&gt;(@&lt;/span&gt;&lt;span class="nf"&gt;nums&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Algorithm::&lt;/span&gt;&lt;span class="nv"&gt;Combinatorics&lt;/span&gt; &lt;span class="sx"&gt;qw/subsets/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;List::&lt;/span&gt;&lt;span class="nv"&gt;Util&lt;/span&gt; &lt;span class="sx"&gt;qw/sum0/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;subsets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$#nums&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$s&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@$position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;# Only proper subsets of size 2 or more&lt;/span&gt;
        &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;# Subsets are indexed at zero, but positions at 1, so compensate in sum&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$sumPosition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;sum0&lt;/span&gt;  &lt;span class="nv"&gt;@$position&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$sumNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;sum0&lt;/span&gt; &lt;span class="nv"&gt;@nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;@$position&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$sumNumbers&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$sumPosition&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;push&lt;/span&gt; &lt;span class="nv"&gt;@result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;@nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;@$position&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;@result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Your Lips Move, But I Can't Hear What You're Saying
&lt;/h3&gt;

&lt;p&gt;Explanatory notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;use Algorithm::Combinatorics qw/subsets/&lt;/code&gt; -- This function creates an iterator to generate consecutive subsets from a given list of members. We're going to pass it a list of positions, from 0 to the last index of &lt;code&gt;@nums&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;use List::Util qw/sum0/&lt;/code&gt; -- &lt;code&gt;sum0&lt;/code&gt; handles empty lists by returning zero instead of an error, as &lt;code&gt;sum&lt;/code&gt; does. That shouldn't come up in this particular function, but I generally use &lt;code&gt;sum0&lt;/code&gt; as my default, because I invariably get a warning from &lt;code&gt;sum&lt;/code&gt; about an empty array and end up changing it anyway.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;my $size = scalar(@$position)&lt;/code&gt; -- the size of the &lt;code&gt;position&lt;/code&gt; array comes up repeatedly, so let's get a handle on it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;my @sumPosition = $size + sum0(...)&lt;/code&gt; -- The sum we're looking for is based on using positions numbered from 1, but we have them numbered from 0. We need to add 1 to each of the positions, which is the same as adding the number of positions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;my @sumNumbers = sum0 @nums[ @$position ]&lt;/code&gt; -- Here's why I wanted positions to be indexed from zero: so that they could be used in a hash slice to extract the corresponding numbers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;push @result, [@nums[@$position]]&lt;/code&gt; -- the result of this function is going to be a reference to an array of arrays (it's array reference turtles all the way down). Once again, the hash slice, now encased in &lt;code&gt;[]&lt;/code&gt; to create an array reference.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  That'll Keep You Going Through the Show
&lt;/h2&gt;

&lt;p&gt;This function answers the question, but it leaves two things undone.&lt;/p&gt;

&lt;p&gt;First, the order of the lists is unspecified. There's no apparent reason for the order in the examples, and I quickly found out that the &lt;code&gt;subsets&lt;/code&gt; iterator doesn't return subsets in the same order as the examples.&lt;/p&gt;

&lt;p&gt;To create unit tests, I want to check that arrays contain the same members, but order doesn't matter. In the &lt;code&gt;Test2&lt;/code&gt; suite, this can be accomplished by putting the expected elements into a bag data structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;runTest&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Test2::&lt;/span&gt;&lt;span class="nv"&gt;V0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Test2::Tools::&lt;/span&gt;&lt;span class="nv"&gt;Compare&lt;/span&gt; &lt;span class="sx"&gt;qw/bag item/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$check&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nv"&gt;$check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;bag&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;item&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="nv"&gt;item&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="nv"&gt;item&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="nv"&gt;item&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="nv"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nv"&gt;is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;sseq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;$check&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Example 1&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our bags are checked, so ...&lt;/p&gt;

&lt;h2&gt;
  
  
  Come On, It's Time To Go
&lt;/h2&gt;

&lt;p&gt;Second, to display the output, we have to unwrap the array references and render them as formatted strings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;sseq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@ARGV&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's going on here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sseq(@ARGV)-&amp;gt;@*&lt;/code&gt; -- Call our function, using the command line arguments, and dereference it (which yields an array of array references).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;map { ... }&lt;/code&gt; -- Transform each of the array references&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"(" . join(", ", $_-&amp;gt;@*) . ")"&lt;/code&gt; -- &lt;code&gt;$_&lt;/code&gt; is a reference to an array, so &lt;code&gt;$_-&amp;gt;@*&lt;/code&gt; is the list of elements in the array. Make it a comma-separated string, encased in parentheses.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;say join ", ", ...&lt;/code&gt; -- output each of those parenthesized strings, separated by commas&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  I Have Become Comfortably Numb
&lt;/h2&gt;

&lt;p&gt;Equilibrium achieved.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
    </item>
    <item>
      <title>PWC 370 Scramble On, Scramblin' Man</title>
      <dc:creator>Bob Lied</dc:creator>
      <pubDate>Sun, 26 Apr 2026 13:16:46 +0000</pubDate>
      <link>https://forem.com/boblied/pwc-370-scramble-on-scramblin-man-5god</link>
      <guid>https://forem.com/boblied/pwc-370-scramble-on-scramblin-man-5god</guid>
      <description>&lt;p&gt;If your girlfriend has been kidnapped by Gollum and the Evil One, and there's nothing you can do, perhaps console yourself with a small programming problem while you listen to &lt;a href="https://www.youtube.com/watch?v=LzGBQerkvWs" rel="noopener noreferrer"&gt;Ramble On&lt;/a&gt; or &lt;a href="https://www.youtube.com/watch?v=7KeoYzHPKF0&amp;amp;list=PLusK5fwzmlBpaXektW8_VODHazPZFyPC4&amp;amp;index=1" rel="noopener noreferrer"&gt;Ramblin' Man'&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-370/#TASK2" rel="noopener noreferrer"&gt;PWC 370 Task 2: Scramble String&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Task
&lt;/h3&gt;

&lt;p&gt;You are given two strings A and B of the same length. Write a script to return true if string B is a scramble of string A otherwise return false. String B is a scramble of string A if A can be transformed into B by a single (recursive) scramble operation. A scramble operation is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the string consists of only one character, return the string.&lt;/li&gt;
&lt;li&gt;Divide the string X into two non-empty parts.&lt;/li&gt;
&lt;li&gt;Optionally, exchange the order of those parts.&lt;/li&gt;
&lt;li&gt;Optionally, scramble each of those parts.&lt;/li&gt;
&lt;li&gt;Concatenate the scrambled parts to return a single string.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str1 = "abc"&lt;/code&gt;, &lt;code&gt;$str2 = "acb"&lt;/code&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;true&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;split: ["a", "bc"]&lt;/li&gt;
&lt;li&gt;split: ["a", ["b", "c"]]&lt;/li&gt;
&lt;li&gt;swap: ["a", ["c", "b"]]&lt;/li&gt;
&lt;li&gt;concatenate: "acb"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str1 = "abcd"&lt;/code&gt;, &lt;code&gt;$str2 = "cdba"&lt;/code&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;true&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;split: ["ab", "cd"]&lt;/li&gt;
&lt;li&gt;swap: ["cd", "ab"]&lt;/li&gt;
&lt;li&gt;split: ["cd", ["a", "b"]]&lt;/li&gt;
&lt;li&gt;swap: ["cd", ["b", "a"]]&lt;/li&gt;
&lt;li&gt;concatenate: "cdba"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str1 = "hello"&lt;/code&gt;, &lt;code&gt;$str2 = "hiiii"&lt;/code&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str1 = "ateer"&lt;/code&gt;, &lt;code&gt;$str2 = "eater"&lt;/code&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str1 = "abcd"&lt;/code&gt;, &lt;code&gt;$str2 = "bdac"&lt;/code&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;false&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Ramblin' Scramblin' Thinkin' Part
&lt;/h3&gt;

&lt;p&gt;This could go two ways: (1) generate every possible scramble of &lt;code&gt;str1&lt;/code&gt; and then look for &lt;code&gt;str2&lt;/code&gt;; or (2) do a breadth-first or depth-first search for &lt;code&gt;str2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The possible number of scrambles could explode. For a length of &lt;em&gt;n&lt;/em&gt;, there will be &lt;em&gt;n&lt;/em&gt;-1 splits, and then the &lt;em&gt;n&lt;/em&gt;-1 string will have &lt;em&gt;n&lt;/em&gt;-2 splits, and so on, so we're looking at factorial complexity. Let's not generate every possible scramble unless we have to.&lt;/p&gt;

&lt;p&gt;For a search, we'd be trying to match the front or back halves of the two strings, and then recursing on the parts that didn't match. There are finite possibilities for partial matches.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A simple swap gets us from &lt;code&gt;str1&lt;/code&gt; to &lt;code&gt;str2&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  str1:    ---  ++++++++++
  str2:    ++++++++++  --- 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The head or tail of &lt;code&gt;str1&lt;/code&gt; matches the corresponding head or tail of str2, requiring us to recurse on the shorter string that
didn't yet match.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   str1:   ===  [??????????]    ||    [???]   ==========
            |     scramble           scramble      |
            |         |                 |          |
   str2:   ===  [.*#.*#.*#.]    ||    [.*#]   ==========
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The head or tail of &lt;code&gt;str1&lt;/code&gt; matches the back or front of &lt;code&gt;str2&lt;/code&gt;. Similar to the case above, except that a swap is required before we recurse.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   str1:  ===  [??????????]   ||   [???] =========
                     /               \
             scramble                 scramble
               /                              \
   str2:  [.*#.*#.*#.]  ===   ||   ========= [.*#]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A Bold Strategy, Cotton. Let's see if that works out for him.
&lt;/h3&gt;

&lt;p&gt;After an embarrassing amount of trial and error (you might say I was scrambling), my solution converged on this longer-than-usual recursive function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;isScramble&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str1&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;str2&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;depth&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;"")&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;%remember&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;%remember&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$depth&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="p"&gt;"";&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;$str1&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;$str2&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;exists&lt;/span&gt; &lt;span class="nv"&gt;$remember&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="si"&gt;${depth}&lt;/span&gt;&lt;span class="s2"&gt;CACHED &lt;/span&gt;&lt;span class="si"&gt;$key&lt;/span&gt;&lt;span class="s2"&gt; = &lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$remember&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="p"&gt;":"&lt;/span&gt;&lt;span class="s2"&gt;false&lt;/span&gt;&lt;span class="p"&gt;"));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$remember&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$remember&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$len&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$remember&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$str1&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="nv"&gt;$str2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$len&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;# $_ is the length of the left substring (head), $len-$_ is length of right (tail)&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;  &lt;span class="nv"&gt;$head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="nv"&gt;$tail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$s2head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$s2tail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$s2front&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$len&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;# length of $tail, on left side&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$s2back&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;          &lt;span class="c1"&gt;# length of $head, on right side&lt;/span&gt;

        &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="si"&gt;${depth}&lt;/span&gt;&lt;span class="s2"&gt;Compare [&lt;/span&gt;&lt;span class="si"&gt;$head&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;$tail&lt;/span&gt;&lt;span class="s2"&gt;] &amp;lt;&amp;gt; s2head/&lt;/span&gt;&lt;span class="si"&gt;$s2tail&lt;/span&gt;&lt;span class="s2"&gt;] (&lt;/span&gt;&lt;span class="si"&gt;$s2front&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;$s2back&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$tail$head&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="nv"&gt;$str2&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="si"&gt;${depth}&lt;/span&gt;&lt;span class="s2"&gt;FOUND &lt;/span&gt;&lt;span class="si"&gt;$str2&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$remember&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$head&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="nv"&gt;$s2head&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="si"&gt;${depth}&lt;/span&gt;&lt;span class="s2"&gt;HH, compare &lt;/span&gt;&lt;span class="si"&gt;$tail&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt;&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;$s2tail&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$remember&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;isScramble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$s2tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="si"&gt;$depth&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$head&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="nv"&gt;$s2back&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="si"&gt;${depth}&lt;/span&gt;&lt;span class="s2"&gt;HB, compare &lt;/span&gt;&lt;span class="si"&gt;$tail&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt;&amp;gt; s2front&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$remember&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;isScramble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$s2front&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="si"&gt;$depth&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$tail&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="nv"&gt;$s2tail&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="si"&gt;${depth}&lt;/span&gt;&lt;span class="s2"&gt;TT, compare &lt;/span&gt;&lt;span class="si"&gt;$head&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt;&amp;gt; s2head&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$remember&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;isScramble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$s2head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="si"&gt;$depth&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$tail&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="nv"&gt;$s2front&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="si"&gt;${depth}&lt;/span&gt;&lt;span class="s2"&gt;TF, compare &lt;/span&gt;&lt;span class="si"&gt;$head&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt;&amp;gt; s2back&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$remember&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;isScramble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$s2back&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="si"&gt;$depth&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="si"&gt;${depth}&lt;/span&gt;&lt;span class="s2"&gt;No pairs, recurse with &lt;/span&gt;&lt;span class="si"&gt;$head&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;$s2head&lt;/span&gt;&lt;span class="s2"&gt; and &lt;/span&gt;&lt;span class="si"&gt;$tail&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;$s2tail&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$remember&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; 
                   &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;isScramble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$s2head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="si"&gt;$depth&lt;/span&gt;&lt;span class="p"&gt;")&lt;/span&gt;
                  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;isScramble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$s2tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="si"&gt;$depth&lt;/span&gt;&lt;span class="p"&gt;")&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;isScramble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$s2back&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="si"&gt;$depth&lt;/span&gt;&lt;span class="p"&gt;")&lt;/span&gt;
                  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;isScramble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$s2front&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="si"&gt;$depth&lt;/span&gt;&lt;span class="p"&gt;")&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="si"&gt;${depth}&lt;/span&gt;&lt;span class="s2"&gt;NOT FOUND &lt;/span&gt;&lt;span class="si"&gt;$key&lt;/span&gt;&lt;span class="s2"&gt; = false (caching)&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$remember&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The function starts out with setting up a cache for partial results. During development, I added this near the end of the process, but it shows up at the top of the function, so let's discuss it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recursive search algorithms usually benefit from caching known results. Our worst case is that &lt;code&gt;str1&lt;/code&gt; can't be scrambled into &lt;code&gt;str2&lt;/code&gt;, in which case we'll end up doing the whole exponential tree of possibilities. I expect caching partial results would pay off.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;%remember&lt;/code&gt; hash is my cache, and it's a &lt;code&gt;state&lt;/code&gt; variable so that it persists across recursive calls. But that means it also persists across invocations for different test cases, so it could yield wrong answers unless I initialize it at the top level of the recursion.&lt;/li&gt;
&lt;li&gt;The cache is filled by using in-line assignment every time a result is returned, which is kind of cutely readable, I think.&lt;/li&gt;
&lt;li&gt;Should I have used &lt;a href="https://perldoc.perl.org/Memoize" rel="noopener noreferrer"&gt;&lt;code&gt;Memoize&lt;/code&gt;&lt;/a&gt;? Maybe. But that caches values based on the arguments passed to the function, and one of my arguments is the &lt;code&gt;depth&lt;/code&gt; to which I've recursed. That means cache misses depending on how I got down the search tree, so I opted for do-it-yourself memo-ization.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The function begins by dispensing with the easy cases: having a result in the cache, matching strings, and strings of the wrong length.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Then, for each division of &lt;code&gt;str1&lt;/code&gt;, let's have at hand the substrings that we might be dealing with from both &lt;code&gt;str1&lt;/code&gt; and &lt;code&gt;str2&lt;/code&gt;. There's a little tour-de-force of &lt;code&gt;substr&lt;/code&gt; uses here, splitting the strings at a midpoint, and using negative offsets.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Most of the body of the function is testing which pairs match up, if any, and doing the appropriate recursion of what remains.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The last case, where neither the head nor the tail of &lt;code&gt;str1&lt;/code&gt; has a matching complement in &lt;code&gt;str2&lt;/code&gt;, requires us to recurse on both pieces, and in either order.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;I used logging liberally, because the function is only obvious in hindsight and took me longer than I'd like to admit. The &lt;code&gt;$depth&lt;/code&gt; argument is mostly a convenience for indenting the log statements appropriately -- notice that it gets longer by two spaces at each recursion. My setup for logging uses &lt;code&gt;Log::Log4perl&lt;/code&gt; in easy mode. It's part of my boilerplate for PWC solutions and looks like this:&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Getopt::&lt;/span&gt;&lt;span class="nv"&gt;Long&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$Verbose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$DoTest&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;GetOptions&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;$DoTest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;$Verbose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Log::&lt;/span&gt;&lt;span class="nv"&gt;Log4perl&lt;/span&gt; &lt;span class="sx"&gt;qw(:easy)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;Log::&lt;/span&gt;&lt;span class="nv"&gt;Log4perl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;easy_init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="s"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$Verbose&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$DEBUG&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$INFO&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="s"&gt;layout&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%d{HH:mm:ss.SSS} %p{1} %m%n&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nv"&gt;$logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Log::&lt;/span&gt;&lt;span class="nv"&gt;Log4perl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;get_logger&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
    </item>
    <item>
      <title>PWC 367 Overlapping Oddities</title>
      <dc:creator>Bob Lied</dc:creator>
      <pubDate>Sun, 05 Apr 2026 14:15:46 +0000</pubDate>
      <link>https://forem.com/boblied/pwc-367-oddity-ln3</link>
      <guid>https://forem.com/boblied/pwc-367-oddity-ln3</guid>
      <description>&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-367/#TASK1" rel="noopener noreferrer"&gt;Task 1, Maximum Odd Binary&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;It's the week of the &lt;a href="https://en.wikipedia.org/wiki/Artemis_II" rel="noopener noreferrer"&gt;Artemis 2&lt;/a&gt; mission to the moon, and we have a problem about odd numbers. I'd call that a &lt;a href="https://www.youtube.com/watch?v=iYYRH4apXDo" rel="noopener noreferrer"&gt;Space Oddity&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Task Description
&lt;/h3&gt;

&lt;p&gt;You are given a binary string that has at least one ‘1’.&lt;/p&gt;

&lt;p&gt;Write a script to rearrange the bits in such a way that the resulting binary number is the maximum odd binary number and return the resulting binary string. The resulting string can have leading zeros.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example 1:&lt;/strong&gt; &lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "1011"&lt;/code&gt;, &lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;"1101"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example 2:&lt;/strong&gt; &lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "100"&lt;/code&gt;, &lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;"001"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example 3:&lt;/strong&gt; &lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "111000"&lt;/code&gt;, &lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;"110001"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example 4:&lt;/strong&gt; &lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "0101"&lt;/code&gt;,&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;"1001"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example 5:&lt;/strong&gt; &lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "1111"&lt;/code&gt;, &lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;"1111"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Task Cogitation
&lt;/h3&gt;

&lt;p&gt;To be as large as possible, a binary number must have all its 1s in the most-significant bits. To be odd, the least significant bit must be a one. So, what has to happen is that all the 1s shift to the left, one shifts to the right, and all the zeroes form a space between them. &lt;/p&gt;

&lt;p&gt;I see three possible solutions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sort: sort the bits so that the 1s are on the left, the 0s on the right, and then rotate a 1 into the right-most position.&lt;/li&gt;
&lt;li&gt;Split: make a pass over the bits, creating a pile of 1s and a pile of 0s. Form the required output string from the piles.&lt;/li&gt;
&lt;li&gt;Count: There's no need to move the bits around. Count how many 1s there are. Conjure a string of 1s, and a string of 0s.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Task Implementation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Solution 1: Sorting
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;mobSort&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@bits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="ow"&gt;cmp&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;push&lt;/span&gt; &lt;span class="nv"&gt;@bits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt; &lt;span class="nv"&gt;@bits&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;("",&lt;/span&gt; &lt;span class="nv"&gt;@bits&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sort in descending order to put 1s on the left&lt;/li&gt;
&lt;li&gt;Rotate by taking the bit on the left and pushing it onto the right.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Solution 2: Splitting
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;mobSplit&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@bit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;"",&lt;/span&gt; &lt;span class="p"&gt;""&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$bit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;.=&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$bit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$bit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$bit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I want a group of 0s and a group of 1s. That's an array of size two, conveniently indexed by &lt;code&gt;[0]&lt;/code&gt; and &lt;code&gt;[1]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For each 0 or 1, append to its string.&lt;/li&gt;
&lt;li&gt;To form the output, use the four-argument form of &lt;code&gt;substr&lt;/code&gt;, which replaces a substring. In the string of 1s, insert the string of 0s just before the zero-length string in front of the last bit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Solution 3: Counting
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;mobCount&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$zero&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;tr/0/0/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;$zero&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="nv"&gt;$zero&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The output will be the same length as the input.&lt;/li&gt;
&lt;li&gt;The number of zeroes can be counted by the &lt;a href="https://perldoc.perl.org/perlfaq4#How-can-I-count-the-number-of-occurrences-of-a-substring-within-a-string?" rel="noopener noreferrer"&gt;Perl FAQ idiom&lt;/a&gt; of using the &lt;code&gt;tr///&lt;/code&gt; operator -- it returns the number of substitutions.&lt;/li&gt;
&lt;li&gt;Now we know how any 1s and 0s we need, so replicate them appropriately.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Task Benchmark
&lt;/h3&gt;

&lt;p&gt;It's too trivial a problem to be concerned about performance, but let's benchmark it anyway.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;               Rate   sorting splitting  counting
sorting    128205/s        --      -28%      -95%
splitting  178571/s       39%        --      -93%
counting  2500000/s     1850%     1300%        --
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm not surprised that sorting is slowest (it's an O(&lt;em&gt;n_log_n&lt;/em&gt;) algorithm). I am a little surprised how much faster counting is.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-367/#TASK2" rel="noopener noreferrer"&gt;Task 2, Conflict Events&lt;/a&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Task Description
&lt;/h2&gt;

&lt;p&gt;You are given two events' start and end time.&lt;/p&gt;

&lt;p&gt;Write a script to find out if there is a conflict between the two events. A conflict happens when two events have some non-empty intersection.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example 1:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Input: &lt;code&gt;@event1 = ("10:00", "12:00")&lt;/code&gt; &lt;code&gt;@event2 = ("11:00", "13:00")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Output: true&lt;/li&gt;
&lt;li&gt;Both events overlap from "11:00" to "12:00".&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 2:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Input: &lt;code&gt;@event1 = ("09:00", "10:30")&lt;/code&gt; &lt;code&gt;@event2 = ("10:30", "12:00")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Output: false&lt;/li&gt;
&lt;li&gt;Event1 ends exactly at 10:30 when Event2 starts.
Since the problem defines intersection as non-empty, exact boundaries touching is not a conflict.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 3:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Input: &lt;code&gt;@event1 = ("14:00", "15:30")&lt;/code&gt; &lt;code&gt;@event2 = ("14:30", "16:00")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Output: true&lt;/li&gt;
&lt;li&gt;Both events overlap from 14:30 to 15:30.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Example 4:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input: &lt;code&gt;@event1 = ("08:00", "09:00")&lt;/code&gt; &lt;code&gt;@event2 = ("09:01", "10:00")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Output: false&lt;/li&gt;
&lt;li&gt;There is a 1-minute gap from "09:00" to "09:01".&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Example 5:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input: &lt;code&gt;@event1 = ("23:30", "00:30")&lt;/code&gt; &lt;code&gt;@event2 = ("00:00", "01:00")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Output: true&lt;/li&gt;
&lt;li&gt;They overlap from "00:00" to "00:30".&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Task Cogitation
&lt;/h3&gt;

&lt;p&gt;The string form of time is annoying to work with. The first thing to do is to convert the time to a minute of the day. As we learned last week, there are 1440 minutes in a day. And as we learned long ago, there are &lt;a href="https://www.youtube.com/watch?v=XNbwiGbETSQ" rel="noopener noreferrer"&gt;525,600 minutes&lt;/a&gt; in a year, but that's not relevant. Stay focused.&lt;/p&gt;

&lt;p&gt;Once we have the times converted, then we have a problem in detecting overlapping ranges. I know how to do that. The examples highlight the edge cases.&lt;/p&gt;

&lt;p&gt;Example 5 throws a curve: the ranges can cross midnight. There will be math involving modulo operators.&lt;/p&gt;

&lt;p&gt;I'm going to break this down into small pieces.&lt;/p&gt;

&lt;h3&gt;
  
  
  Task Solution
&lt;/h3&gt;

&lt;p&gt;What I'm going for is: does the range of event 1 overlap with the range of event 2? That means I need a function to see if ranges overlap, which means I need a function to convert times to ranges, which means I need functions to convert time strings to numbers. Let's pop that stack.&lt;/p&gt;

&lt;h4&gt;
  
  
  Subtask: Time conversion
&lt;/h4&gt;

&lt;p&gt;Very straightforward. I'm assuming times have been validated and are in the specified format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;toMinute&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;hhmm&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="nv"&gt;$hhmm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$minute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$m&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$minute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Subtask: Event range
&lt;/h4&gt;

&lt;p&gt;Here's where we isolate the problem of spanning midnight. We figure out how long the event is, using a 24-hour clock modulo operation. Then, replace the beginning of the range by subtracting the duration from the end. That means we might get a negative number for the beginning, but that's okay -- it represents a time before midnight.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;toRange&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;minBeg&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;minEnd&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$minEnd&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$minBeg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;1440&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$minEnd&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$minEnd&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Subtask: Range overlap
&lt;/h4&gt;

&lt;p&gt;Given two ranges, whether they overlap depends on where their edges line up.&lt;/p&gt;

&lt;p&gt;I like &lt;code&gt;use enum&lt;/code&gt; as a way to introduce a little readability. It's a very efficent module, and quite flexible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;isOverlap&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;range1&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;range2&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;enum&lt;/span&gt; &lt;span class="sx"&gt;qw( BEG=0 END=1 )&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$range1&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$range2&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;BEG&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$range1&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;BEG&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$range2&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Composition of the solution
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;isConflict&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;event1&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;event2&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;isOverlap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;toRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;toMinute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;$event1&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
                     &lt;span class="nv"&gt;toRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;toMinute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;$event2&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given all the pieces, the solution falls into place.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;map { toMinute() "&lt;/code&gt; -- convert the time strings into pairs of numbers that we can do arithmetic with.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;toRange( map {} )&lt;/code&gt; - convert pairs of points in time into ranges that might span midnight.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isOverlap(...)&lt;/code&gt; - the answer is the result of checking for range overlap.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
    </item>
    <item>
      <title>PWC 366, Task 2, Valid Times</title>
      <dc:creator>Bob Lied</dc:creator>
      <pubDate>Fri, 27 Mar 2026 14:31:07 +0000</pubDate>
      <link>https://forem.com/boblied/pwc-366-task-2-valid-times-38h5</link>
      <guid>https://forem.com/boblied/pwc-366-task-2-valid-times-38h5</guid>
      <description>&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-366/#TASK2" rel="noopener noreferrer"&gt;PWC 366 Task 2, Valid Times&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Here we are at another Weekly Challenge, &lt;a href="https://www.youtube.com/watch?v=Qr0-7Ds79zo" rel="noopener noreferrer"&gt;ticking away the moments&lt;/a&gt; that make up a dull day. Fritter and waste the hours in an off-hand way. Kicking around on a piece of ground in your home town, waiting for someone or something to show you the way. Here's a way.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Requirements Phase
&lt;/h3&gt;

&lt;p&gt;You are given a time in the form ‘HH:MM’. The earliest possible time is ‘00:00’ and the latest possible time is ‘23:59’. In the string time, the digits represented by the ‘?’ symbol are unknown, and must be replaced with a digit from 0 to 9. Write a script to return the count of different ways we can make it a valid time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example 1&lt;/strong&gt;: &lt;em&gt;Input&lt;/em&gt;: &lt;code&gt;$time = "?2:34"&lt;/code&gt;, &lt;em&gt;Output&lt;/em&gt;: &lt;code&gt;3&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;02:34, 12:34, 22:34&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 2&lt;/strong&gt;: &lt;em&gt;Input&lt;/em&gt;: &lt;code&gt;$time = "?4:?0"&lt;/code&gt;, &lt;em&gt;Output&lt;/em&gt;: &lt;code&gt;12&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Combinations of hours 04 and 14, with minutes 00, 10, 20, 30, 40, 50&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 3&lt;/strong&gt;: &lt;em&gt;Input&lt;/em&gt;: &lt;code&gt;$time = "??:??"&lt;/code&gt;, &lt;em&gt;Output&lt;/em&gt;: &lt;code&gt;1440&lt;/code&gt;
&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 4&lt;/strong&gt;: &lt;em&gt;Input&lt;/em&gt;: &lt;code&gt;$time = "?3:45"&lt;/code&gt;, &lt;em&gt;Output&lt;/em&gt;: &lt;code&gt;3&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;03:45, 13:45, 23:45&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 5&lt;/strong&gt;: &lt;em&gt;Input&lt;/em&gt;: &lt;code&gt;$time = "2?:15"&lt;/code&gt;, &lt;em&gt;Output&lt;/em&gt;: &lt;code&gt;4&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;20:15, 21:15, 22:15, 23:15&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Design Phase
&lt;/h3&gt;

&lt;p&gt;My first thought is that it would be fun to make some kind of iterator or generator that replaces each &lt;code&gt;?&lt;/code&gt; with its valid possibilities. My second thought is, "Nah, that seems like a lot of work." And since the cardinal virtue of Perl programming is laziness, I moved on to something simpler.&lt;/p&gt;

&lt;p&gt;There are 24 valid hours and 60 valid minutes. The total valid combinations is the cross-product of the two. Let's go with that.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Implementation Phase
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;validTime&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;@hour&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;00&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;23&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;@minute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;00&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;59&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sr"&gt;s/\?/./gr&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/:/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$time&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="sr"&gt;/$h/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;@hour&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="sr"&gt;/$m/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;@minute&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;state&lt;/code&gt; variables -- These reference lists only need to be set up once, and only in the scope of this function. That's what &lt;code&gt;state&lt;/code&gt; does.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;'00' .. '23'&lt;/code&gt; -- The &lt;code&gt;..&lt;/code&gt; sequence operator has the nice feature that if you want leading zeroes, you get them. Looking at you, &lt;code&gt;bash&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;split(/:/, $time)&lt;/code&gt; -- Divide the input into its components. As in so many weekly challenge tasks, I'm assuming that the input has already been sanitized and is showing up here in a valid form.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;map { ... }&lt;/code&gt; -- Do something to both the hours and the minutes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;s/\?/./gr&lt;/code&gt; -- The something is to replace &lt;code&gt;?&lt;/code&gt; with &lt;code&gt;.&lt;/code&gt; so that it becomes a regular expression. The &lt;code&gt;?&lt;/code&gt; is a meta-character, so it needs to be quoted. Adding the &lt;code&gt;r&lt;/code&gt; flag yields the modified string; otherwise &lt;code&gt;s///g&lt;/code&gt; would yield the number of substitutions, which is not useful in this context.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;my ($h, $m) = ...&lt;/code&gt; -- Declaring and initializing two variables from a list of two things.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;(grep /$h/, @hour)&lt;/code&gt; -- Select a list of the valid hours that can match the &lt;code&gt;$h&lt;/code&gt; pattern. This is in a scalar context (numerical multiplication), so the scalar value will result -- the number of matches. Similarly for minutes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We only need the count, so multiply the two. We could have generated the list of valid times by using the hours and minutes returned from &lt;code&gt;grep&lt;/code&gt; in array context, but (I believe I already mentioned this), lazy.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Delivery Phase
&lt;/h3&gt;

&lt;p&gt;And there you have it. You run and you run to catch up with the sun, but it's sinking, and racing around to come up behind you again. The sun is the same in a relative way, but you're older, shorter of breath, and one day closer to death. But at least you solved weekly challenge 366.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
    </item>
    <item>
      <title>PWC 366 Count Prefixes: Could We Start Again, Please</title>
      <dc:creator>Bob Lied</dc:creator>
      <pubDate>Fri, 27 Mar 2026 13:37:30 +0000</pubDate>
      <link>https://forem.com/boblied/pwc-366-count-prefixes-could-we-start-again-please-19kc</link>
      <guid>https://forem.com/boblied/pwc-366-count-prefixes-could-we-start-again-please-19kc</guid>
      <description>&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-366/#TASK1" rel="noopener noreferrer"&gt;PCW 366, Task 1, Count Prefix&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;So many prefixes, starting from the beginning over and over. It reminds me of &lt;a href="https://www.youtube.com/watch?v=I4lfETL2fm4" rel="noopener noreferrer"&gt;"Could We Start Again, Please?"&lt;/a&gt; from &lt;em&gt;Jesus Christ, Superstar&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Task
&lt;/h3&gt;

&lt;p&gt;You are given an array of words and a string (contains only lowercase English letters). Write a script to return the number of words in the given array that are a prefix of the given string.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example 1:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input&lt;/em&gt;: &lt;code&gt;@array = ("a", "ap", "app", "apple", "banana")&lt;/code&gt;, &lt;code&gt;$str = "apple"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;4&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 2:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input&lt;/em&gt;: &lt;code&gt;@array = ("cat", "dog", "fish")&lt;/code&gt;, &lt;code&gt;$str = "bird"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Output: &lt;code&gt;0&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 3&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input&lt;/em&gt;: &lt;code&gt;@array = ("hello", "he", "hell", "heaven", "he")&lt;/code&gt;, &lt;code&gt;$str = "hello"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output&lt;/em&gt;: &lt;code&gt;4&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 4&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input&lt;/em&gt;: &lt;code&gt;@array = ("", "code", "coding", "cod")&lt;/code&gt;, &lt;code&gt;$str = "coding"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output&lt;/em&gt;: &lt;code&gt;3&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 5&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input&lt;/em&gt;: &lt;code&gt;@array = ("p", "pr", "pro", "prog", "progr", "progra", "program")&lt;/code&gt;, &lt;code&gt;$str = "program"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output&lt;/em&gt;: &lt;code&gt;7&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  An Obvious Solution Using a Regular Expression
&lt;/h3&gt;

&lt;p&gt;The first thing that springs to mind is to do a pattern match of each string in &lt;code&gt;@array&lt;/code&gt; against the string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;countPrefix&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;scalar&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;m/^$_/&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;$array&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Because of the way Perl passes array arguments, I've chosen to invert the order and pass the scalar string first. Then, I further chose to pass an array reference instead of a copy of the array, for premature optimization.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;grep&lt;/code&gt; returns different things depending on whether it's in scalar context or array context. I want the scalar value always (the count of the number of matches).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A Less-obvious Solution Using a Regular Expression
&lt;/h3&gt;

&lt;p&gt;Another way to approach the problem is to look at it from the point of view of the string. What are all the possible prefixes? Then see if any of the &lt;code&gt;@array&lt;/code&gt; values is in that set of alternatives. The programming task in this solution is to build a regular expression that matches every possible prefix.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;onerex&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;|&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;scalar&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="sr"&gt;/^(?:$regex)$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$array&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;0 .. length(str)&lt;/code&gt; -- generates the sequence of possible prefix lengths, including the empty string (one of the given examples implies that an empty string should be considered a valid prefix).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;map { substr($str, 0, $_) }&lt;/code&gt; -- For each length, extract the prefix of that length, giving an array of increasingly longer strings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;join('|', ...)&lt;/code&gt; -- Combine the strings into a set of alternatives that can be used in a regular expression.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;$array-&amp;gt;@*&lt;/code&gt; -- Post-fix notation for de-referencing the array. I like it; Perl classic would probably use &lt;code&gt;@$array&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/^(...)$/&lt;/code&gt; -- The potential prefixes must be anchored at the start and end to exactly match one of the alternatives in &lt;code&gt;$regex&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/^(?:...)/&lt;/code&gt; -- We need the parentheses for grouping, but we don't need to extract the pattern match. The &lt;code&gt;?:&lt;/code&gt; assertion does that; it saves the overhead of extracting the match and then ignoring it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A Solution Using String Compare
&lt;/h3&gt;

&lt;p&gt;All of the strings involved in this task are constants; there's no meta-characters or repetitions that require a regular expression. It could be done with string compares, and that would probably be more efficient.  Let's find out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;precmp&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;scalar&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;$array&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implicitly loop over &lt;code&gt;@array&lt;/code&gt;. For each possible prefix, extract the same length of string from the front of &lt;code&gt;$str&lt;/code&gt; and see if they match exactly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Benchmark
&lt;/h2&gt;

&lt;p&gt;Let's see how the solutions compare. I'll make up a string of modest length, and an array with a lot of words.  For the purpose of the benchmark, I don't really care how many prefixes are found.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;runBenchmark&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;Benchmark&lt;/span&gt; &lt;span class="sx"&gt;qw/cmpthese/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;abcdefghijklmnopqrstuvwxy&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
  &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="sx"&gt;qw(lorem ipsum dolor sit amet consectetur adipiscing elit e tiam elit neque venenatis ut dolor consectetur iaculis venenatis arcu in in terdum mauris eget neque venenatis dapibus sed finibus varius sapien quis mal esuada fusce libero augue vulputate sit amet faucibus at feugiat at l ectus maecenas vehicula sem metus nullam lobortis massa et est vulputate f acilisis in tempus arcu metus vitae aliquam nibh sodales ac sed vitae era t nec nisl laoreet fringilla aliquam et lobortis purus ut a tristique nisi nec molest ie arcu duis mattis ultrices nisl eget consectetur donec ac lo rem non augue bibendum tincidunt interdum quis velit in gravida metus vitae)&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;


    &lt;span class="nv"&gt;cmpthese&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$repeat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;regex&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;countPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="s"&gt;substr&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;precmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="s"&gt;onerex&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;onerex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now for the unveil:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;           Rate  regex onerex substr
regex    8636/s     --   -73%   -95%
onerex  31447/s   264%     --   -83%
substr 185185/s  2044%   489%     --
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The solution with simple string compares wins by blowout. This is not surprising to me. The overhead of setting up regular expressions and doing their evaluation is mostly unnecessary for this task, and the string compares are highly optimized operations in Perl.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
    </item>
    <item>
      <title>PWC 362 Echo Chamber</title>
      <dc:creator>Bob Lied</dc:creator>
      <pubDate>Thu, 26 Feb 2026 15:34:51 +0000</pubDate>
      <link>https://forem.com/boblied/pwc-362-echo-chamber-1dn1</link>
      <guid>https://forem.com/boblied/pwc-362-echo-chamber-1dn1</guid>
      <description>&lt;p&gt;The musical accompaniment must obviously be Pink Floyd's &lt;a href="https://www.youtube.com/watch?v=KBca3xf-j3o" rel="noopener noreferrer"&gt;Echoes&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Task
&lt;/h2&gt;

&lt;p&gt;You are given a string containing lowercase letters.&lt;/p&gt;

&lt;p&gt;Write a script to transform the string based on the index position of each character (starting from 0). For each character at position i, repeat it i + 1 times.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input&lt;/em&gt;: &lt;code&gt;"abca"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output&lt;/em&gt;: &lt;code&gt;"abbcccaaaa"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Index 0: "a" -&amp;gt; repeated 1 time  -&amp;gt; "a"&lt;br&gt;
Index 1: "b" -&amp;gt; repeated 2 times -&amp;gt; "bb"&lt;br&gt;
Index 2: "c" -&amp;gt; repeated 3 times -&amp;gt; "ccc"&lt;br&gt;
Index 3: "a" -&amp;gt; repeated 4 times -&amp;gt; "aaaa"&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Thoughts, Both Profound and Superficial
&lt;/h2&gt;

&lt;p&gt;A string transformation problem, an ideal domain for Perl. There are at least three approaches I can see.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Treat it as a regular expression problem, substituting each character for &lt;em&gt;n&lt;/em&gt; copies of itself. It wouldn't be Perl if at least one of the more-than-one-way-do-its didn't have more punctuation than letters.&lt;/li&gt;
&lt;li&gt;Treat it as a list problem. Separate the string into a list of characters and map each list element into &lt;em&gt;n&lt;/em&gt; copies of itself.&lt;/li&gt;
&lt;li&gt;Treat it as a string generation problem. Build a new string out of bits of the original.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In any case, the linchpin is going to be the &lt;a href="https://perldoc.perl.org/perlop#Multiplicative-Operators" rel="noopener noreferrer"&gt;repetition operator, &lt;code&gt;x&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Solutions
&lt;/h2&gt;
&lt;h3&gt;
  
  
  A Regular Expression Substition
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;echoRE&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;English&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/(.)/$1 x $LAST_MATCH_END[1]/g&lt;/span&gt;&lt;span class="nv"&gt;er&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Several features of Perl regular expressions come into play.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We need to do some math in the substitution to replicate the characters. To put executable code into the substitution, we use the &lt;em&gt;/e&lt;/em&gt; flag.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We need the index of the character we're replacing. Perl regular expressions have many useful side effects that are available in special variables. When using a capture group, the indexes of the beginning and end of the matching text are available in the &lt;code&gt;@-&lt;/code&gt; and &lt;a href="https://perldoc.perl.org/perlvar#@LAST_MATCH_END" rel="noopener noreferrer"&gt;&lt;code&gt;@+&lt;/code&gt; special array variables&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The default result of a &lt;code&gt;s///g&lt;/code&gt; global substitution is the number of replacements made, which can be useful in some contexts, but not this one. The &lt;em&gt;/r&lt;/em&gt; flag changes the behavior so that it results in the modified string instead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I'm conceding a tiny bit to readability. &lt;code&gt;use English&lt;/code&gt; lets me use &lt;code&gt;$LAST_MATCH_END&lt;/code&gt; in place of &lt;code&gt;$+&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the breakdown of willing the regular expression into existence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;s///gr&lt;/code&gt; -- It's going to be a global substituion (every character), and we want the result.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;s/(.)//gr&lt;/code&gt; -- Capture every character, no matter what it is.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;s/(.)/$1 x .../gre&lt;/code&gt; -- Replicate the captured character the appropriate number of times. Add the &lt;code&gt;e&lt;/code&gt; flag to execute this expression.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;s/(.)/$1 x $+[1]/gre&lt;/code&gt; -- After a visit to the Perl references (just to spite AI, I used an actual book of genuine paper), we find that the offset of the captured character is in the &lt;code&gt;@-&lt;/code&gt; and &lt;code&gt;@+&lt;/code&gt; special variables. Using &lt;code&gt;@+&lt;/code&gt; (end of the match) instead of &lt;code&gt;@-&lt;/code&gt; takes care of the &lt;code&gt;index+1&lt;/code&gt; annoyance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As evidenced by the step above, I can't remember the special variables, so I add &lt;code&gt;use English&lt;/code&gt; to get the name &lt;code&gt;LAST_MATCH_END&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  A List Solution
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;echoMap&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt; &lt;span class="p"&gt;"",&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This solution turns each character into a longer string of repeated characters. It maps indexes into a corresponding string of the correct length.&lt;/p&gt;
&lt;h3&gt;
  
  
  A String-building solution
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;echoStr&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;"";&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;indexed&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;.=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$c&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A variation on the list processing, this one builds a string with repeated concatenation. Instead of building a list with &lt;code&gt;map&lt;/code&gt; and then &lt;code&gt;join&lt;/code&gt;-ing it into a result, this one goes straight to the string.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;split&lt;/code&gt; gives me the individual characters as a list. It's more efficient than repeated calls to &lt;code&gt;substr&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since we need both the character and its index, I relied on my favorite variation of the &lt;code&gt;for&lt;/code&gt; loop using &lt;code&gt;indexed&lt;/code&gt; to conveniently give me variable names.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Comparison
&lt;/h2&gt;

&lt;p&gt;As always, I'm curious about the relative efficiency of the solutions. Here's a benchmark result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;           Rate    regex  mapjoin splitstr
regex    2365/s       --     -43%     -57%
mapjoin  4118/s      74%       --     -25%
splitstr 5469/s     131%      33%       --
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm a little surprised that regular expressions didn't fare better. I hypothesize that the addition of executable code in the substitution is a significant cost.&lt;/p&gt;

&lt;p&gt;I'm not surprised that string building won. Iterating over lists and manipulating strings are a core strength of Perl, and those operations have no doubt been optimized to heck over the decades.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
    </item>
    <item>
      <title>PWC 360 Pertaining to a subtlety of sorting</title>
      <dc:creator>Bob Lied</dc:creator>
      <pubDate>Wed, 11 Feb 2026 17:05:44 +0000</pubDate>
      <link>https://forem.com/boblied/pwc-360-pertaining-to-a-subtlety-of-sorting-39b4</link>
      <guid>https://forem.com/boblied/pwc-360-pertaining-to-a-subtlety-of-sorting-39b4</guid>
      <description>&lt;p&gt;It's been a while since I commented on a Weekly Challenge solution, but here we are at week 360. Such a useful number. So divisible, so circular. It deserves twenty minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-360/#TASK2" rel="noopener noreferrer"&gt;Task 2: Word Sorter&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The task
&lt;/h3&gt;

&lt;p&gt;You are given a sentence.  Write a script to order words in the given&lt;br&gt;
sentence alphabetically but keep the words themselves unchanged.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Example 1 Input: $str = "The quick brown fox"
#           Output: "brown fox quick The"
# Example 2 Input: $str = "Hello    World!   How   are you?"
#           Output: "are Hello How World! you?"
# Example 3 Input: $str = "Hello"
#           Output: "Hello"
# Example 4 Input: $str = "Hello, World! How are you?"
#           Output: "are Hello, How World! you?"
# Example 5 Input: $str = "I have 2 apples and 3 bananas!"
#           Output: "2 3 and apples bananas! have I"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The thoughts
&lt;/h3&gt;

&lt;p&gt;This should be quite simple: split the words, sort them, put them back together. The sort should be case-insensitive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nb"&gt;join&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;cmp&lt;/span&gt; &lt;span class="nb"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Creeping doubt #1
&lt;/h4&gt;

&lt;p&gt;Is converting to lowercase with &lt;code&gt;lc&lt;/code&gt; the right way to do case-insenstive compares? Not really. Perl has the &lt;code&gt;fc&lt;/code&gt; -- fold-case -- function to take care of subtleties in Unicode. We won't see those in simple ASCII text, but for the full rabbit hole, start with the &lt;a href="https://perldoc.perl.org/functions/fc" rel="noopener noreferrer"&gt;documentation of fc&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Creeping doubt #2
&lt;/h4&gt;

&lt;p&gt;Doing the case conversion inside the sort means that we will invoke that every time there's a string comparison, which will be quite redundant. We could (probably?) speed it up by pre-calculating the conversions once.&lt;/p&gt;

&lt;h3&gt;
  
  
  The solution
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;sorter&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt;
        &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;cmp&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;fc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This solution uses the idiom of Schwartzian transformation. Every word gets turned into a pair of [original_word, case_folded_word]. That array of pairs gets sorted, and then we select the original words out of the sorted pairs. This is best read bottom-up.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;split(" ", $str)&lt;/code&gt; -- turns the string into an array of words, where words are loosely defined by being white-space separated.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;map { [$_, fc($_)] }&lt;/code&gt; -- every word turns into a pair: the original, and its case-folded variation. The result is a list of array references.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sort { $a-&amp;gt;[1] cmp $b-&amp;gt;[1] }&lt;/code&gt; -- sort by the case-folded versions. The result is still a list of array references.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;map { $_-&amp;gt;[0] }&lt;/code&gt; -- select the original word from each pair&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;join " "&lt;/code&gt; -- Return a single string, where the words are separated by one space.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Does it blend?
&lt;/h3&gt;

&lt;p&gt;A quick benchmark shows that it is indeed faster to pre-calculate the case folding. This example used a text string of about 60 words.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;           Rate oneline  pre_lc
oneline 32258/s      --    -45%
pre_lc  58140/s     80%      --
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My intuition says that when the strings are much shorter, the overhead of the transform might not offset the gains in the sort, but as is so often true, my intuition is crap. This is the result for a string of five words:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oneline  470588/s      --    -59%
pre_lc  1142857/s    143%      --
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
    </item>
    <item>
      <title>PWC 353 To each (array) his own</title>
      <dc:creator>Bob Lied</dc:creator>
      <pubDate>Mon, 22 Dec 2025 15:12:56 +0000</pubDate>
      <link>https://forem.com/boblied/pwc-353-to-each-array-his-own-23o8</link>
      <guid>https://forem.com/boblied/pwc-353-to-each-array-his-own-23o8</guid>
      <description>&lt;p&gt;&lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-353/" rel="noopener noreferrer"&gt;This week's challenges&lt;/a&gt; were early and on the easy side, which was appreciated as the holidays loom. The musical interlude this week ignores the challenge tasks in favor of seasonal light jazz; I have Spotify playing "Winter's Songs: A Windham Hill Christmas."&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-353/#TASK1" rel="noopener noreferrer"&gt;Task 1: Max Words&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Task
&lt;/h3&gt;

&lt;p&gt;You are given an array of sentences. Write a script to return the maximum number of words that appear in a single sentence.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example 1:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;@sentences = ("Hello world", "This is a test", "Perl is great")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; 4&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;An easy one -- an early Xmas gift? Split each sentence into words and count them, then take the maximum. Completely ignoring all the complexities of punctuation and internationalization, it's a one-liner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;maxWords&lt;/span&gt;&lt;span class="err"&gt;(@&lt;/span&gt;&lt;span class="nf"&gt;sentence&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;List::&lt;/span&gt;&lt;span class="nv"&gt;Util&lt;/span&gt; &lt;span class="sx"&gt;qw/max/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;max&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;@sentence&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only thing mildly tricky here is transforming the list of words into a count. Inside the body of the &lt;code&gt;map&lt;/code&gt; block, we're in array context, so &lt;code&gt;split&lt;/code&gt; will return a list. Coercing it with &lt;code&gt;scalar&lt;/code&gt; gives the count.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-353/#TASK2" rel="noopener noreferrer"&gt;Task 2: Validate Coupon&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Task
&lt;/h3&gt;

&lt;p&gt;You are given three arrays, &lt;code&gt;@codes&lt;/code&gt;, &lt;code&gt;@names&lt;/code&gt; and &lt;code&gt;@status&lt;/code&gt;. Write a script to validate codes in the given array. A code is valid when the following conditions are true:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;codes[i]&lt;/code&gt; is non-empty and consists only of alphanumeric characters (&lt;code&gt;a-z, A-Z, 0-9&lt;/code&gt;) and underscores (&lt;code&gt;_&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;names[i]&lt;/code&gt; is one of the following four categories: "electronics", "grocery", "pharmacy", "restaurant".&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;status[i]&lt;/code&gt; is true.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Return an array of booleans indicating validity: &lt;code&gt;output[i]&lt;/code&gt; is true if and only if &lt;code&gt;codes[i]&lt;/code&gt;, &lt;code&gt;names[i]&lt;/code&gt; and &lt;code&gt;status[i]&lt;/code&gt; are all valid.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example 1:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input&lt;/em&gt;:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@codes  = ("A123", "B_456", "C789", "D@1", "E123")&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@names  = ("electronics", "restaurant", "electronics", "pharmacy", "grocery")&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@status = ("true", "false", "true", "true", "true")&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;(true, false, true, false, true)&lt;/code&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Thoughts
&lt;/h3&gt;

&lt;p&gt;The volume of text for this one was daunting at first glance, but it turns out to be mostly example data and actually quite easy.&lt;/p&gt;

&lt;p&gt;The validation is straight-forward. &lt;code&gt;@codes&lt;/code&gt; is a regular expression match; &lt;code&gt;@names&lt;/code&gt; is a keyword lookup from a dictionary table (hash); and &lt;code&gt;@status&lt;/code&gt; is just a string compare.&lt;/p&gt;

&lt;p&gt;We'll be operating on parallel arrays. I see two ways of doing it. First, we could use a variable to loop over the indexes. That's going to yield code with a lot of array subscripts. Or second, we could use &lt;code&gt;each_array&lt;/code&gt; from &lt;code&gt;List::More::Utils&lt;/code&gt; to do the indexing for us. I'm curious which is more efficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  To the code-sleigh, Rudolph!
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Loop with &lt;code&gt;indexed&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;valid&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;%ValidName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;electronics&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;grocery&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="s"&gt;pharmacy&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;restaurant&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@valid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;indexed&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$valid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!~&lt;/span&gt; &lt;span class="sr"&gt;m/[^a-zA-Z0-9_]/&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$valid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;exists&lt;/span&gt; &lt;span class="nv"&gt;$ValidName&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$valid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;=&lt;/span&gt; &lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;@valid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Passing multiple arrays as subroutine parameters implies using references. We could use traditional &lt;a href="https://perldoc.perl.org/perlsub#Prototypes" rel="noopener noreferrer"&gt;prototype attributes&lt;/a&gt; to make it possible to pass arrays, but let's not.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;state %ValidName&lt;/code&gt; -- These are valid keywords for the &lt;code&gt;@names&lt;/code&gt; input array. Using &lt;code&gt;state&lt;/code&gt; makes this a static table, initialized only the first time the subroutine is entered.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@valid&lt;/code&gt; -- Our output array, same size as the input array. Assume they're all valid and turn elements false if any check fails.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;indexed&lt;/code&gt; -- My favorite recent Perl improvement. Returns both the index and the value from an array during a &lt;code&gt;for&lt;/code&gt; loop.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;valid-&amp;gt;[$i] &amp;amp;&amp;amp;= ...&lt;/code&gt; -- Any failing test will turn the value to false.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$code-&amp;gt;[$i] !~ m/[^a-zA-Z0-9_]/&lt;/code&gt; -- The code has to consist entirely of valid characters, or conversely, it must &lt;em&gt;not&lt;/em&gt; match (&lt;code&gt;!~&lt;/code&gt;) anything that contains a character other than those. Later I went back to look up exactly what &lt;code&gt;\w&lt;/code&gt; and &lt;code&gt;\W&lt;/code&gt; mean in Perl regular expressions and realized that I could have used that instead of the character classes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;exists $ValidName{...}&lt;/code&gt; -- Use &lt;code&gt;exists&lt;/code&gt; explicitly to return a boolean value.  A simple lookup that fails would return &lt;code&gt;undef&lt;/code&gt;, and will make the result of the expression &lt;code&gt;undef&lt;/code&gt; instead of &lt;code&gt;false&lt;/code&gt;. Although &lt;code&gt;undef&lt;/code&gt; is treated as false in many contexts, it failed the unit test.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;return \@valid&lt;/code&gt; -- Return a reference. This is convenient for the  &lt;code&gt;is()&lt;/code&gt; function from the &lt;code&gt;Test2::V0&lt;/code&gt; unit testing framework, and returning a reference also improves performance by avoiding an array copy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Loop with array iterator
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;validEach&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;%ValidName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;electronics&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;grocery&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="s"&gt;pharmacy&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;restaurant&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@valid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;List::&lt;/span&gt;&lt;span class="nv"&gt;MoreUtils&lt;/span&gt; &lt;span class="sx"&gt;qw/each_arrayref/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$ea&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;each_arrayref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$ea&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;push&lt;/span&gt; &lt;span class="nv"&gt;@valid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$c&lt;/span&gt; &lt;span class="o"&gt;!~&lt;/span&gt; &lt;span class="sr"&gt;m/[^a-zA-Z0-9_]/&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;exists&lt;/span&gt; &lt;span class="nv"&gt;$ValidName&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$s&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;             &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;@valid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is basically the same function, except that the explicit indexing has been replaced by an iterator.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;each_arrayref&lt;/code&gt; -- There's an &lt;code&gt;each_array&lt;/code&gt; function, but since we have array references, this one is convenient.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;my $ea = ...&lt;/code&gt; -- Creates an iterator over the three arrays.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ea-&amp;gt;()&lt;/code&gt; -- Call the iterator. &lt;code&gt;ea&lt;/code&gt; is the equivalent of a function pointer, and this is function dereference syntax.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;while ( my ($c, $n, $s) = ea-&amp;gt;() )&lt;/code&gt; -- Each call to the iterator returns a tuple of the next element from each of the &lt;code&gt;$code&lt;/code&gt;, &lt;code&gt;$name&lt;/code&gt;, and &lt;code&gt;$status&lt;/code&gt; arrays.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;push @valid, ...&lt;/code&gt; -- The same three checks as before, but building the list instead of modifying it, because we don't have an index in hand.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Performance check
&lt;/h4&gt;

&lt;p&gt;I think the iterator version is a little cleaner, because it eliminates the clutter of repeated array subscripts. But I was curious how it compared in efficiency, so I set up a quick benchmark using the examples.&lt;/p&gt;

&lt;p&gt;It turns out that the explicit indexing is about twice as efficient as the &lt;code&gt;each_arrayref&lt;/code&gt; iterator. Still gonna use it, though.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl ch-2.pl -b 100000
             Rate iterator forindex
iterator  72464/s       --     -47%
forindex 136986/s      89%       --
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To do the benchmarking, I set up the examples as an array of test cases, and used &lt;code&gt;Benchmark::cmpthese&lt;/code&gt; to do a lot of iterations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;runBenchmark&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;Benchmark&lt;/span&gt; &lt;span class="sx"&gt;qw/cmpthese/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nv"&gt;cmpthese&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$repeat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;forindex&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;@case&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nv"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;codes&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;names&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="s"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;@case&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nv"&gt;validEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;codes&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;names&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the input data looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@case&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Example 1&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
      &lt;span class="s"&gt;codes&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A123&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;        &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B_456&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;      &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C789&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;        &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;D@1&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;      &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;E123&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;names&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electronics&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;restaurant&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electronics&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pharmacy&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;grocery&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;        &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;false&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;      &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;        &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;     &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;expect&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Example 2&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
      &lt;span class="s"&gt;codes&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Z_9&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;      &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AB_12&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;       &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;G01&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;     &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X99&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;         &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;names&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pharmacy&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electronics&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;grocery&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electronics&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;     &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;        &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;false&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;   &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;        &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;expect&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Example 3&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
      &lt;span class="s"&gt;codes&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_123&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;       &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;         &lt;span class="p"&gt;'',&lt;/span&gt;            &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Coupon_A&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alpha&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;names&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;restaurant&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electronics&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electronics&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pharmacy&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;grocery&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;       &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;        &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;false&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;       &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;     &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;expect&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Example 4&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
      &lt;span class="s"&gt;codes&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ITEM_1&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;      &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ITEM_2&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;      &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ITEM_3&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;  &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ITEM_4&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;names&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electronics&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electronics&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;grocery&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;grocery&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;        &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;        &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;expect&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Example 5&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
      &lt;span class="s"&gt;codes&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CAFE_X&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;     &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ELEC_100&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FOOD_1&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;  &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DRUG_A&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;   &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ELEC_99&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;names&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;restaurant&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electronics&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;grocery&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pharmacy&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electronics&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;       &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;        &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;     &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;false&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;expect&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
    </item>
    <item>
      <title>PWC 352 Five is the one-liest number</title>
      <dc:creator>Bob Lied</dc:creator>
      <pubDate>Fri, 19 Dec 2025 22:27:21 +0000</pubDate>
      <link>https://forem.com/boblied/pwc-352-five-is-the-one-liest-number-487e</link>
      <guid>https://forem.com/boblied/pwc-352-five-is-the-one-liest-number-487e</guid>
      <description>&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-352/#TASK1" rel="noopener noreferrer"&gt;Task 1: Match String&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Task
&lt;/h3&gt;

&lt;p&gt;You are given an array of strings. Write a script to return all strings that are a substring of another word in the given array in the order they occur.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example 1:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;@words = ("cat", "cats", "dog", "dogcat", "dogcat", "rat", "ratcatdogcat")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;("cat", "dog", "dogcat", "rat")&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Deep Thoughts
&lt;/h3&gt;

&lt;p&gt;Example 1 implies a couple of constraints. A complete match counts as a substring. Words may be repeated in the input. Repeated words are not duplicated in the output. The output order must match the input order. Noted.&lt;/p&gt;

&lt;p&gt;For each word, we'll need to take it out of the list, check for substrings, and then put it back for the next round. A relatively simple way of doing that would be to shift it off the front of the list, do what needs to be done, and then return it by pushing it onto the back.&lt;/p&gt;

&lt;p&gt;I don't see much of a way of getting around the idea that every word must be compared to every other word, so we're looking at an O(&lt;em&gt;n&lt;/em&gt;&lt;sup&gt;2&lt;/sup&gt;) performance algorithm.&lt;/p&gt;

&lt;p&gt;One possibility for reducing the operation count might be to compare a pair of words both ways. If I have &lt;code&gt;$w1&lt;/code&gt; and &lt;code&gt;$w2&lt;/code&gt; in hand, I can check both directions for substring-i-ness. That way, instead of having to loop over the entire NxN matrix, we would only have to loop over the upper or lower triangle of the matrix. It's fewer looping operations, but still the same number of string comparisons. But it would mean more complexity in keeping track of what's been checked, so, meh.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;matchString&lt;/span&gt;&lt;span class="err"&gt;(@&lt;/span&gt;&lt;span class="nf"&gt;words&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;List::&lt;/span&gt;&lt;span class="nv"&gt;Util&lt;/span&gt; &lt;span class="sx"&gt;qw/any/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%seen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@match&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;@words&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt; &lt;span class="nv"&gt;@words&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;push&lt;/span&gt; &lt;span class="nv"&gt;@match&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;$seen&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;any&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;@words&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;push&lt;/span&gt; &lt;span class="nv"&gt;@words&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;@match&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a hash (&lt;code&gt;%seen&lt;/code&gt;) to eliminate duplicates, and coincidentally optimize a little by not searching multiple times.&lt;/li&gt;
&lt;li&gt;The main loop is once per word, so simply count. Normally, I would prefer something obviously tied to the array (like &lt;code&gt;for (@words)&lt;/code&gt;), but since I'm changing the array within the loop, I don't want to have to think too hard about whether the iterator remains valid after removing and adding an element.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;index&lt;/code&gt; is a cheaper operation than a regular expression match. Benchmarking bears this out -- it's about three times more efficient in my environment and test data.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;List::Util::any&lt;/code&gt; stops as soon as something works, so it's cheaper than &lt;code&gt;grep&lt;/code&gt;, which would evaluate the entire list every time. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-352/#TASK2" rel="noopener noreferrer"&gt;Task 2: Binary Prefix&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Task
&lt;/h3&gt;

&lt;p&gt;You are given an array, &lt;code&gt;@nums&lt;/code&gt;, where each element is either 0 or 1.&lt;/p&gt;

&lt;p&gt;Define xi as the number formed by taking the first &lt;code&gt;i+1&lt;/code&gt; bits of &lt;code&gt;@nums&lt;/code&gt; (from &lt;code&gt;$nums[0&lt;/code&gt;] to &lt;code&gt;$nums[i]&lt;/code&gt;) and interpreting them as a binary number, with &lt;code&gt;$nums[0]&lt;/code&gt; being the most significant bit.&lt;/p&gt;

&lt;p&gt;For example: If &lt;code&gt;@nums = (1, 0, 1)&lt;/code&gt;, then:&lt;br&gt;
  x0 = 1 (binary 1)&lt;br&gt;
  x1 = 2 (binary 10)&lt;br&gt;
  x2 = 5 (binary 101)&lt;/p&gt;

&lt;p&gt;For each &lt;em&gt;i&lt;/em&gt;, check whether xi is divisible by 5.&lt;/p&gt;

&lt;p&gt;Write a script to return an array &lt;code&gt;@answer&lt;/code&gt; where &lt;code&gt;$answer[i]&lt;/code&gt; is true if &lt;em&gt;x&lt;/em&gt;i is divisible by 5, otherwise false.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example 1:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Input: &lt;code&gt;@nums = (0,1,1,0,0,1,0,1,1,1)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Output: (true, false, false, false, false, true, true, false, false, false)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Binary numbers formed (decimal values):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;         0:   0  (false)
        01:   1  (false)
       011:   3  (false)
      0110:   6  (false)
     01100:  12  (false)
    011001:  25  ( true)
   0110010:  50  ( true)
  01100101: 101  (false)
 011001011: 203  (false)
0110010111: 407  (false)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Deep Thoughts
&lt;/h3&gt;

&lt;p&gt;Weird flex, but OK.&lt;/p&gt;

&lt;p&gt;This puts me in mind of bit-twiddling with C code, but bit-twiddling in Perl is equally possible. The other alternative is probably to build strings and do binary number conversions by prefixing with '0b'.&lt;/p&gt;

&lt;p&gt;I kind of want to do a list-based solution, using &lt;code&gt;map&lt;/code&gt; to convert each 0 or 1 to a &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;, but I think that would be obfuscating a pretty simple loop.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;bpre&lt;/span&gt;&lt;span class="err"&gt;(@&lt;/span&gt;&lt;span class="nf"&gt;nums&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@isFive&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;defined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$bit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt; &lt;span class="nv"&gt;@nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;$bit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;push&lt;/span&gt; &lt;span class="nv"&gt;@isFive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;@isFive&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Destroy the input by shifting a 1 or 0 off the left until the list is gone.&lt;/li&gt;
&lt;li&gt;Do bit operations to form a new number.&lt;/li&gt;
&lt;li&gt;Build an answer array consisting of boolean values.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Musical Interlude
&lt;/h2&gt;

&lt;p&gt;The solution to task 1 reminds me of Katy Perry's &lt;a href="https://www.youtube.com/watch?v=C-jAPrdc3PI" rel="noopener noreferrer"&gt;Hot N Cold&lt;/a&gt; -- "You're yes, then you're no. You're in, then you're out."&lt;/p&gt;

&lt;p&gt;And for Task 2, &lt;a href="https://www.youtube.com/watch?v=is6AYSCWwKM" rel="noopener noreferrer"&gt;Mambo Number 5&lt;/a&gt; is oddly appropriate. "Take one step left and one step right, One to the front and one to the side. Clap your hands once and clap your hands twice, And if it looks like this, then you're doin' it right."&lt;/p&gt;

</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
    </item>
    <item>
      <title>PWC 350 Good Substring / Shuffle Pairs</title>
      <dc:creator>Bob Lied</dc:creator>
      <pubDate>Wed, 03 Dec 2025 02:48:23 +0000</pubDate>
      <link>https://forem.com/boblied/pwc-350-good-substring-shuffle-pairs-3gfn</link>
      <guid>https://forem.com/boblied/pwc-350-good-substring-shuffle-pairs-3gfn</guid>
      <description>&lt;h2&gt;
  
  
  Musical Interlude
&lt;/h2&gt;

&lt;p&gt;The movie version of &lt;em&gt;Wicked&lt;/em&gt; is in theaters right now, so I am reminded of the song &lt;a href="https://www.youtube.com/watch?v=Y8YMfgu92hQ" rel="noopener noreferrer"&gt;For Good&lt;/a&gt; -- but I'm gonna link to the Broadway version, because I'm classy like that. It's relevant to programming in Perl because "I don't know if I've been changed for the better, but I have been changed for good."  For part two, &lt;a href="https://www.youtube.com/watch?v=HQZBaJAngH8" rel="noopener noreferrer"&gt;Lido Shuffle&lt;/a&gt; by Boz Scaggs.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-350/#TASK1" rel="noopener noreferrer"&gt;Task 1: Good Substrings&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Task
&lt;/h3&gt;

&lt;p&gt;You are given a string.  Write a script to return the number of good substrings of length three in the given string.  A string is good if there are no repeated characters.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Example 1: Input $str = "abcaefg", Output: 5

&lt;ul&gt;
&lt;li&gt;Good substrings of length 3: abc, bca, cae, aef and efg&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Example 2: Input: $str = "xyzzabc", Output: 3&lt;/li&gt;

&lt;li&gt;Example 3: Input: $str = "aababc", Output: 1&lt;/li&gt;

&lt;li&gt;Example 4: Input: $str = "qwerty",  Output: 4&lt;/li&gt;

&lt;li&gt;Example 5: Input: $str = "zzzaaa",  Output: 0&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Think-y Part
&lt;/h2&gt;

&lt;p&gt;There's probably a regular expression for this, but I'm not going to find it. Do the simplest thing that works: take three characters at a time and see if they're different.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code-y Part
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;goodSubstring&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$good&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$#s&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$third&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="nv"&gt;$good&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$first&lt;/span&gt; &lt;span class="ow"&gt;ne&lt;/span&gt; &lt;span class="nv"&gt;$second&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$first&lt;/span&gt; &lt;span class="ow"&gt;ne&lt;/span&gt; &lt;span class="nv"&gt;$third&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$second&lt;/span&gt; &lt;span class="ow"&gt;ne&lt;/span&gt; &lt;span class="nv"&gt;$third&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$good&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start by turning the string into a list of characters. It could be done with &lt;code&gt;substr&lt;/code&gt;, but that would be untidy.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@s[$_, $_+1, $_+2]&lt;/code&gt; -- With a nod to readability, I'll extract three consecutive characters with an array slice. It occurs to me that I'll always have two of the next three characters in hand at the bottom of the loop, so doing a complete splice every time could probably be optimized, but I declare it "good" enough. &lt;/li&gt;
&lt;li&gt;Since there's exactly three characters in play, check for uniqueness in the most obvious way.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-350/#TASK2" rel="noopener noreferrer"&gt;Task 2:Shuffle Pairs&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Task
&lt;/h3&gt;

&lt;p&gt;If two integers A &amp;lt;= B have the same digits but in different orders, we say that they belong to the same shuffle pair if and only if there is an integer k such that A = B * k. k is called the witness of the pair. For example, 1359 and 9513 belong to the same shuffle pair, because 1359 * 7 = 9513.&lt;/p&gt;

&lt;p&gt;Interestingly, some integers belong to several different shuffle pairs. For example, 123876 forms one shuffle pair with 371628, and another with 867132, as 123876 * 3 = 371628, and 123876 * 7 = 867132.&lt;/p&gt;

&lt;p&gt;Write a function that for a given &lt;code&gt;$from&lt;/code&gt;, &lt;code&gt;$to&lt;/code&gt;, and &lt;code&gt;$count&lt;/code&gt; returns the number of integers &lt;code&gt;$i&lt;/code&gt; in the range &lt;code&gt;$from &amp;lt;= $i &amp;lt;= $to&lt;/code&gt; that belong to at least &lt;code&gt;$count&lt;/code&gt; different shuffle pairs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Example 1:

&lt;ul&gt;
&lt;li&gt;Input: $from = 1, $to = 1000, $count = 1&lt;/li&gt;
&lt;li&gt;Output: 0&lt;/li&gt;
&lt;li&gt;There are no shuffle pairs with elements less than 1000.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Example 2:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input: $from = 1500, $to = 2500, $count = 1&lt;/li&gt;
&lt;li&gt;Output: 3&lt;/li&gt;
&lt;li&gt;There are 3 integers between 1500 and 2500 that belong to shuffle pairs.

&lt;ul&gt;
&lt;li&gt;1782, the other element is 7128 (witness 4)&lt;/li&gt;
&lt;li&gt;2178, the other element is 8712 (witness 4)&lt;/li&gt;
&lt;li&gt;2475, the other element is 7425 (witness 3)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Example 3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input: $from = 1_000_000, $to = 1_500_000, $count = 5&lt;/li&gt;
&lt;li&gt;Output: 2&lt;/li&gt;
&lt;li&gt;There are 2 integers in the given range that belong to 5 different shuffle pairs.

&lt;ul&gt;
&lt;li&gt;1428570 pairs with 2857140, 4285710, 5714280, 7142850, and 8571420&lt;/li&gt;
&lt;li&gt;1429857 pairs with 2859714, 4289571, 5719428, 7149285, and 8579142&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Example 4:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input: $from = 13_427_000, $to = 14_100_000, $count = 2&lt;/li&gt;
&lt;li&gt;Output: 11&lt;/li&gt;
&lt;li&gt;6 integers in the given range belong to 3 different shuffle pairs,&lt;/li&gt;
&lt;li&gt;5 integers belong to 2 different ones.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Example 5:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input: $from = 1030, $to = 1130, $count = 1&lt;/li&gt;
&lt;li&gt;Output: 2&lt;/li&gt;
&lt;li&gt;There are 2 integers between 1020 and 1120 that belong to at least one shuffle pair:

&lt;ul&gt;
&lt;li&gt;1035, the other element is 3105 (witness k = 3)&lt;/li&gt;
&lt;li&gt;1089, the other element is 9801 (witness k = 9)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deliberations
&lt;/h3&gt;

&lt;p&gt;It takes a minute to digest this one.&lt;/p&gt;

&lt;p&gt;I first wondered if there's some algebraic number theory trick that would cut the search space way down, but that made my head hurt, so I moved to doing what computers do best: grinding through a lot of possibilities.&lt;/p&gt;

&lt;p&gt;A bad first thought was to try all combinations of the digits, but that's going to die an excruciating slow death on the crucifix of combinatorics, not to mention that we'd be completely wasting our time on all but a few combinations.&lt;/p&gt;

&lt;p&gt;A better thought is to look only at the multiples of a given number. There are at most 8 multiples of a number in play: the 10th would add a digit, and therefore can't possibly be a reordering. Examples 3 and 4 have a lot of numbers to grind through, but how long can it take, really? It's one banana, Michael; how much could it cost, ten dollars?&lt;/p&gt;

&lt;p&gt;How will I decide that a number is a re-ordering? I think I'll reduce each number to a canonical form where the digits are sorted, then use string compare to see if a multiple has the same canonical form.&lt;/p&gt;

&lt;h3&gt;
  
  
  To the bat-editor, Robin!
&lt;/h3&gt;

&lt;p&gt;First, a little function to turn a number into a canonical form with its digits in sorted order. Turn the number into a list of digits, sort, and then join the digits back into a string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;canonical&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;n&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;("",&lt;/span&gt; &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the main course. I'll want to examine every number in the range &lt;code&gt;$from&lt;/code&gt; to &lt;code&gt;$to&lt;/code&gt;, inclusive.  For each number, I'll want to examine its multiples to see if they have the same digits. I need to count the ones that work so that I can check that there are at least &lt;code&gt;$count&lt;/code&gt; of them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;shufflePair&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$from&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;canonical&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$pair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$multiple&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$multiple&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$max&lt;/span&gt;
                 &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$multiple&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
                 &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$multiple&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;canonical&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$multiple&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="nv"&gt;$base&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$pair&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nv"&gt;$answer&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$pair&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$answer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;my $base = canonical($n)&lt;/code&gt; -- hang on to this for comparison.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;my $max = (9 x length($n))+0;&lt;/code&gt; -- An optimization. The maximum number we need to be concerned with is one that has the same number of digits, but is all 9s.  For example, if &lt;code&gt;$n&lt;/code&gt; is 480, then we are dealing with 3-digit numbers, so the largest possible is 999. That's less than 480*3=1440, so we don't have to examine any of the multiples beyond 480*2.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;for ( 2..9 )&lt;/code&gt; -- These are the only multiples of &lt;code&gt;$n&lt;/code&gt; that could possibly have the same number of digits.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;next if ...&lt;/code&gt; -- Besides the check on &lt;code&gt;$max&lt;/code&gt;, we can make cheap checks on a single digit. If the first or last digit isn't one of the possible digits, we can avoid the overhead of &lt;code&gt;canonical()&lt;/code&gt;, which isn't horrendous, but it does involve allocating lists and a sort.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;canonical($multiple) eq $base&lt;/code&gt; -- This string compare is where we decide if we have a shuffle pair.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$answer++ if $pair &amp;gt;= $count&lt;/code&gt; -- We increment the answer if this number has at least &lt;code&gt;$count&lt;/code&gt; shuffle pairs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This solution takes a few seconds to run the examples. My optimizations to bail early in many cases cut the run time approximately in half (from about 8 seconds to about 4.5).&lt;/p&gt;

</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
    </item>
    <item>
      <title>PWC 349 More complex than it has to be</title>
      <dc:creator>Bob Lied</dc:creator>
      <pubDate>Wed, 26 Nov 2025 03:32:52 +0000</pubDate>
      <link>https://forem.com/boblied/pwc-349-more-complex-than-it-has-to-be-2c7e</link>
      <guid>https://forem.com/boblied/pwc-349-more-complex-than-it-has-to-be-2c7e</guid>
      <description>&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-349/#TASK2" rel="noopener noreferrer"&gt;PWC 349 Task 2: Meeting Point&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Musical Interlude
&lt;/h3&gt;

&lt;p&gt;We're going deep cut from the classic &lt;em&gt;Blood on the Tracks&lt;/em&gt; album by Bob Dylan, &lt;a href="https://www.youtube.com/watch?v=VE6-uc1zr3s" rel="noopener noreferrer"&gt;Meet Me in the Morning&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Task
&lt;/h3&gt;

&lt;p&gt;You are given an instruction string made up of U (up), D (down), L (left) and R (right). Write a script to return true if following the instructions, you meet (0,0) at any point along the sequence.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Example 1:&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$path = "ULD"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;U -&amp;gt; (0,1), L -&amp;gt; (-1,1), D -&amp;gt; (-1, 0)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;em&gt;Example 2:&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$path = "ULDR"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;U -&amp;gt; (0,1), L -&amp;gt; (-1,1), D -&amp;gt; (-1, 0), R -&amp;gt; (0,0)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;em&gt;Example 5:&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$path = "RRUULLDDRRUU"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;RRUULLDD -&amp;gt; (0,0), RRUU -&amp;gt; (2,2)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Deliberation
&lt;/h3&gt;

&lt;p&gt;The first thought is emulate the movement on the grid and see if we end up at (0,0).&lt;/p&gt;

&lt;p&gt;A clever thought arises: to end up back where we began, every Up must be matched with a Down, and every Right must be matched with a Left. So all we really have to do is count moves, right?&lt;/p&gt;

&lt;p&gt;But Example 5 throws a wrench. The path makes a big square and passes through (0,0), but doesn't end there.  I guess I really do need to check every move in the path.&lt;/p&gt;

&lt;p&gt;Second clever thought (this one might be worth keeping): moving around a grid can be like moving in the complex plane. A horizontal move is along the real axis, and a vertical move is along the imaginary axis. If we think of the location as a complex number, then a move is an increment of either the real or the imaginary part.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Code
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Nice try, no cigar
&lt;/h4&gt;

&lt;p&gt;Let's dispense with what didn't work, because it looked good until we hit Example 5.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;meet&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;scalar&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$path&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;m/$_/g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sx"&gt;qw(U D L R)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We'll try to count the number of each direction and see if Ups cancel Downs and Rights cancel Lefts.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;my @m = map {...} qw(U D L R)&lt;/code&gt; -- for each move, map to the number of occurrences of that move in &lt;code&gt;$path&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$path =~ m/$_/g&lt;/code&gt; -- &lt;code&gt;$_&lt;/code&gt; is one of (U,D,L,R). The regular expression match with a &lt;code&gt;g&lt;/code&gt; flag can return a list of all the occurrences of that letter in &lt;code&gt;$path&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scalar(()= ...)&lt;/code&gt; -- assigning the match to an empty list will create an array context, so that &lt;code&gt;m//&lt;/code&gt; will yield a list. Then taking the &lt;code&gt;scalar&lt;/code&gt; of that will give a count. This is a variant of the &lt;code&gt;=()=&lt;/code&gt; &lt;a href="https://metacpan.org/dist/perlsecret/view/lib/perlsecret.pod#Goatse" rel="noopener noreferrer"&gt;Saturn secret operator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Now it only remains to check if the numbers align.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Moving on to something that works
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;meetComplex&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Math::&lt;/span&gt;&lt;span class="nv"&gt;Complex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;$origin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;*i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;%move&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;R&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;*i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;L&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;*i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="s"&gt;U&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;*i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;D&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;*i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$place&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$origin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;uc&lt;/span&gt; &lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$place&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nv"&gt;$move&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$place&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$origin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;use Math::Complex&lt;/code&gt; -- Yes, Perl does complex arithmetic.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;state $origin = (0 + 0*i)&lt;/code&gt; -- Set up a "constant" for the origin. &lt;code&gt;state&lt;/code&gt; makes a variable that is initialized only the first time the function is entered, and limits the scope to the function. &lt;code&gt;Math::Complex&lt;/code&gt; makes it possible to write complex constants in a natural way.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;state %move&lt;/code&gt; -- Set up "constants" for movements. Moving Right and Left affects the real part of the complex number; moving Up and Down affects the imaginary part.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;for ( split(...) )&lt;/code&gt; -- Take the path apart to process each move. I threw in an &lt;code&gt;uc&lt;/code&gt; to make sure we would only have uppercase input.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$place += $move{$_}&lt;/code&gt; -- For each move, change &lt;code&gt;$place&lt;/code&gt; in the complex plane. &lt;code&gt;Math::Complex&lt;/code&gt; overloads operators as expected.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;return true if $place == $origin&lt;/code&gt; -- Complex numbers can be compared, of course.&lt;/li&gt;
&lt;li&gt;If we didn't find (0,0), then the answer is &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
    </item>
    <item>
      <title>PWC 348 String Alike, Convert Time</title>
      <dc:creator>Bob Lied</dc:creator>
      <pubDate>Wed, 19 Nov 2025 03:18:12 +0000</pubDate>
      <link>https://forem.com/boblied/pwc-348-string-alike-convert-time-3nf9</link>
      <guid>https://forem.com/boblied/pwc-348-string-alike-convert-time-3nf9</guid>
      <description>&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-348/#TASK1" rel="noopener noreferrer"&gt;PWC 348 Task 1: String Alike&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Task
&lt;/h3&gt;

&lt;p&gt;You are given a string of even length. Write a script to find out whether the given string can be split into two halves of equal lengths, each with the same non-zero number of vowels.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Example 1:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "textbook"&lt;/code&gt; t&lt;b&gt;e&lt;/b&gt;xt | b&lt;b&gt;oo&lt;/b&gt;k (1, 2)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; false&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Example 2:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "book"&lt;/code&gt; b&lt;b&gt;o&lt;/b&gt; | &lt;b&gt;o&lt;/b&gt;k (1, 1)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; true&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Example 3:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "AbCdEfGh"&lt;/code&gt; &lt;b&gt;A&lt;/b&gt;bCd | &lt;b&gt;E&lt;/b&gt;fGh (1, 1)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; true&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Example 4:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "rhythmmyth"&lt;/code&gt; rhyth | mmyth (0, 0)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; false&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Example 5:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "UmpireeAudio"&lt;/code&gt; &lt;b&gt;U&lt;/b&gt;mp&lt;b&gt;i&lt;/b&gt;r&lt;b&gt;e&lt;/b&gt; | &lt;b&gt;eAu&lt;/b&gt;d&lt;b&gt;io&lt;/b&gt; (3, 5)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; false&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Thoughts
&lt;/h3&gt;

&lt;p&gt;Two steps are required: dividing the string in half, and counting vowels in each half. Let's do the obvious thing with &lt;code&gt;substr&lt;/code&gt; to get the halves, and we can exploit the quirks of &lt;code&gt;tr&lt;/code&gt; to count.&lt;/p&gt;

&lt;p&gt;The examples give us a couple of important test cases: the string can contain uppercase and lowercase; and the string might not have any vowels at all. Also notice that vowels are strictly "aeiou" -- "y" is not counted as a vowel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;strAlike&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$mid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;tr/aeiou//&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                        &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$mid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$mid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;lc($str)&lt;/code&gt; -- eliminate uppercase letters&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$mid = ...&lt;/code&gt; -- assuming even length given, as specified&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;substr($str, 0, mid)&lt;/code&gt; -- the left half&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;substr($str, $mid)&lt;/code&gt; -- the right half (third argument not needed). The two &lt;code&gt;substr&lt;/code&gt; calls result in a list of two strings, which we will pass to ...&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@count = map { }&lt;/code&gt; -- count vowels in each substring and assign into an array of vowel counts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$_ =~ tr/aeiou//&lt;/code&gt; -- Ah, &lt;a href="https://perldoc.perl.org/perlop#Transliteration-Quote-Like-Operators" rel="noopener noreferrer"&gt;&lt;code&gt;tr&lt;/code&gt;&lt;/a&gt;. A quirk of &lt;code&gt;tr&lt;/code&gt; is that it returns a count of replacements made. Replace all the vowels of interest, and there's our count. Another quirk of &lt;code&gt;tr&lt;/code&gt; is that the first argument is &lt;em&gt;not&lt;/em&gt; a regular expression, so there are no brackets for character class here. Note the literal use of &lt;code&gt;aeiou&lt;/code&gt;. Yet another quirk of &lt;code&gt;tr&lt;/code&gt; is that there is no variable interpolation, so it would be awkward to try to parameterize this. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;return ...&lt;/code&gt; -- The description specifies non-zero counts, so the extra condition is needed to make Example 4 work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-348/#TASK2" rel="noopener noreferrer"&gt;PWC 348 Task 2: Convert Time&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Task
&lt;/h3&gt;

&lt;p&gt;You are given two strings, &lt;code&gt;$source&lt;/code&gt; and &lt;code&gt;$target&lt;/code&gt;, containing time in 24-hour time form. Write a script to convert the source into target by performing one of the following operations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add  1 minute&lt;/li&gt;
&lt;li&gt;Add  5 minutes&lt;/li&gt;
&lt;li&gt;Add 15 minutes&lt;/li&gt;
&lt;li&gt;Add 60 minutes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Find the total operations needed to get to the target.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example 1:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$source = "02:30"&lt;/code&gt; &lt;code&gt;$target = "02:45"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;1&lt;/code&gt; (Add 15 minutes)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 2:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$source = "11:55"&lt;/code&gt; &lt;code&gt;$target = "12:15"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;2&lt;/code&gt; (Add 15 minutes, Add 5 minutes)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 3:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$source = "09:00"&lt;/code&gt; &lt;code&gt;$target = "13:00"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;4&lt;/code&gt; (Add 60 minutes four times)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 4:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$source = "23:45"&lt;/code&gt; &lt;code&gt;$target = "00:30"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;3&lt;/code&gt; (Add 15 minutes three times)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example 5:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$source = "14:20"&lt;/code&gt; &lt;code&gt;$target = "15:25"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;2&lt;/code&gt; (Add 60 minutes, Add 5 minutes)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Thoughts
&lt;/h3&gt;

&lt;p&gt;This is a variation on the problem of making change from a set of coins, or finding the combination of stamps to pay postage.&lt;/p&gt;

&lt;p&gt;We need to find the difference in minutes from &lt;code&gt;$source&lt;/code&gt; to &lt;code&gt;$target&lt;/code&gt;. Example 4 shows that we might have to cross midnight.&lt;/p&gt;

&lt;p&gt;I could take the hours and minutes apart and do the math. But I think I'd rather use well-tested modules, so I'll use &lt;code&gt;Time::Piece&lt;/code&gt; to parse the times and find the difference.&lt;/p&gt;

&lt;p&gt;The operation count will be taking the biggest number of chunks possible, so in reverse order: 60, 15, 5, 1.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;source&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;target&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Time::&lt;/span&gt;&lt;span class="nv"&gt;Piece&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Time::&lt;/span&gt;&lt;span class="nv"&gt;Piece&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;strptime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%H:%M&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Time::&lt;/span&gt;&lt;span class="nv"&gt;Piece&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;strptime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%H:%M&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$t&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$min&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$min&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$period&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$min&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;$period&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$min&lt;/span&gt; &lt;span class="o"&gt;%=&lt;/span&gt; &lt;span class="nv"&gt;$period&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;strptime()&lt;/code&gt; -- parse the time strings and create a &lt;code&gt;Time::Piece&lt;/code&gt; object. Without any day information, this will be a time on January 1, 1970, but we don't care.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;($t-$s)-&amp;gt;minutes&lt;/code&gt; -- &lt;code&gt;Time::Piece&lt;/code&gt; objects can be subtracted to get a duration. That duration is actually a &lt;code&gt;Time::Seconds&lt;/code&gt; object, which has a method that returns the duration in minutes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;if ( $min &amp;lt; 0 )&lt;/code&gt; -- This covers the case where &lt;code&gt;$target&lt;/code&gt; is after midnight. We'll add 24 hours of minutes to wrap it around back to positive.&lt;/li&gt;
&lt;li&gt;The rest is math. Reduce by hours, then quarter-hours, then 5-minute blocks. Since the last block is 1 minute, this will always eventually terminate.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
    </item>
  </channel>
</rss>
