<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.5">Jekyll</generator><link href="https://jacoby.github.io//feed.xml" rel="self" type="application/atom+xml" /><link href="https://jacoby.github.io//" rel="alternate" type="text/html" /><updated>2024-03-01T19:13:24+00:00</updated><id>https://jacoby.github.io//feed.xml</id><title type="html">Committed to Memory</title><subtitle>Dave writes code. Sometimes this means he learns something.  He'll probably write it up here.
</subtitle><entry><title type="html">Cans of Worms: Benchmarking finding an element in array</title><link href="https://jacoby.github.io//2024/03/01/cans-of-worms-benchmarking-finding-an-element-in-array.html" rel="alternate" type="text/html" title="Cans of Worms: Benchmarking finding an element in array" /><published>2024-03-01T16:59:02+00:00</published><updated>2024-03-01T16:59:02+00:00</updated><id>https://jacoby.github.io//2024/03/01/cans-of-worms-benchmarking-finding-an-element-in-array</id><content type="html" xml:base="https://jacoby.github.io//2024/03/01/cans-of-worms-benchmarking-finding-an-element-in-array.html"><![CDATA[<p>This starts with comparative programming. I had reason to code some Python recently, and I discovered that there was a built-in to tell if an element is in a list.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="n">word</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">:</span>
    <span class="n">whatever</span><span class="p">(</span><span class="n">word</span><span class="p">)</span>
</code></pre></div></div>

<p>That’s a fairly common test, and there isn’t a One True Solution for it in Perl, with <a href="https://en.wikipedia.org/wiki/Perl#Philosophy">TMTOWTDI</a> and all that.</p>

<p>Offhand, I decided to use <a href="https://metacpan.org/pod/Benchmark">Benchmark</a> to determine what the best way to do the thing. I decided to try to make a determination by creating an array of <strong>X</strong> elements, creating a smaller array of <strong>Y</strong> elements to see if those elements were in that first array, and iterating over them <strong>Z</strong> times.</p>

<p>It’s looking like the first Z, 400 iterations, is large enough for most of the problems, so now I’m looking at filling this:</p>

<table>
  <thead>
    <tr>
      <th>smaller array \ larger array</th>
      <th>1000</th>
      <th>10000</th>
      <th>10000</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>5</strong></td>
      <td>?</td>
      <td>?</td>
      <td>?</td>
    </tr>
    <tr>
      <td><strong>50</strong></td>
      <td>?</td>
      <td>?</td>
      <td>?</td>
    </tr>
    <tr>
      <td><strong>500</strong></td>
      <td>?</td>
      <td>?</td>
      <td>?</td>
    </tr>
  </tbody>
</table>

<h2 id="the-tests">The Tests</h2>

<p>So, what is being tested? The following pseudocode explains the general method,</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>make an array of so many even numbers
make an comparison array of so many numbers
for each value in the comparison array
    check if that value is in the array
    store that result in a hash table
</code></pre></div></div>

<h3 id="first">First</h3>

<p>Here, I’m using <code class="language-plaintext highlighter-rouge">first</code> from the fan-favorite module, <a href="https://metacpan.org/pod/List::Util">List::Util</a>. It’s funny; for all the talking up I do for <code class="language-plaintext highlighter-rouge">min</code> and <code class="language-plaintext highlighter-rouge">max</code> and <code class="language-plaintext highlighter-rouge">sum0</code>, there’s a whole lot I just don’t use.</p>

<p>Note: I use <code class="language-plaintext highlighter-rouge">no warnings</code> in this because Perl throws a warning if <code class="language-plaintext highlighter-rouge">first</code> doesn’t find the thing and returns <code class="language-plaintext highlighter-rouge">undef</code>.</p>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">List::</span><span class="nv">Util</span> <span class="sx">qw{ first }</span><span class="p">;</span>
<span class="k">my</span> <span class="nv">@array</span> <span class="o">=</span> <span class="nb">map</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">*</span> <span class="mi">2</span> <span class="p">}</span> <span class="mi">0</span> <span class="o">..</span> <span class="p">(</span> <span class="mi">10</span> <span class="o">*</span> <span class="nv">$count</span> <span class="p">);</span>
<span class="k">my</span> <span class="nv">@comp</span>  <span class="o">=</span> <span class="mi">1</span> <span class="o">..</span> <span class="nv">$count</span><span class="p">;</span>
<span class="k">my</span> <span class="nv">%is_in_list</span><span class="p">;</span>
<span class="k">for</span> <span class="k">my</span> <span class="nv">$i</span> <span class="p">(</span><span class="nv">@comp</span><span class="p">)</span> <span class="p">{</span>
    <span class="nb">no</span> <span class="nv">warnings</span><span class="p">;</span>
    <span class="k">my</span> <span class="nv">$first</span> <span class="o">=</span> <span class="nv">first</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">==</span> <span class="nv">$i</span> <span class="p">}</span> <span class="nv">@array</span><span class="p">;</span>
    <span class="nv">$is_in_list</span><span class="p">{</span><span class="nv">$i</span><span class="p">}</span> <span class="o">=</span>
        <span class="nb">defined</span> <span class="nv">$first</span> <span class="p">?</span> <span class="p">'</span><span class="s1">true</span><span class="p">'</span> <span class="p">:</span> <span class="p">'</span><span class="s1">false</span><span class="p">';</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Looking further, I’m thinking that <code class="language-plaintext highlighter-rouge">any</code> might be a better named choice, but benchmarking them against each other proved that they’re equivalent for time.</p>

<h3 id="grep">Grep</h3>

<p><a href="https://perldoc.perl.org/functions/grep"><code class="language-plaintext highlighter-rouge">grep</code></a> is a functional subroutine I used well before I had any real understanding of what functional programming is, and here, I’m using it to tell</p>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">my</span> <span class="nv">@array</span> <span class="o">=</span> <span class="nb">map</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">*</span> <span class="mi">2</span> <span class="p">}</span> <span class="mi">0</span> <span class="o">..</span> <span class="p">(</span> <span class="mi">10</span> <span class="o">*</span> <span class="nv">$count</span> <span class="p">);</span>
<span class="k">my</span> <span class="nv">@comp</span>  <span class="o">=</span> <span class="mi">1</span> <span class="o">..</span> <span class="nv">$count</span><span class="p">;</span>
<span class="k">my</span> <span class="nv">%is_in_list</span><span class="p">;</span>
<span class="k">for</span> <span class="k">my</span> <span class="nv">$i</span> <span class="p">(</span><span class="nv">@comp</span><span class="p">)</span> <span class="p">{</span>
    <span class="nv">$is_in_list</span><span class="p">{</span><span class="nv">$i</span><span class="p">}</span> <span class="o">=</span>
        <span class="p">(</span> <span class="nb">grep</span> <span class="p">{</span> <span class="nv">$i</span> <span class="o">==</span> <span class="vg">$_</span> <span class="p">}</span> <span class="nv">@array</span> <span class="p">)</span>
        <span class="p">?</span> <span class="p">'</span><span class="s1">true</span><span class="p">'</span> <span class="p">:</span> <span class="p">'</span><span class="s1">false</span><span class="p">';</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="hash">Hash</h3>

<p>Hash has been my preferred solution for a long while. Here I check everything once and store it in a hash, so that every subsequent test is instantaneous.</p>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">my</span> <span class="nv">@array</span> <span class="o">=</span> <span class="nb">map</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">*</span> <span class="mi">2</span> <span class="p">}</span> <span class="mi">0</span> <span class="o">..</span> <span class="p">(</span> <span class="mi">10</span> <span class="o">*</span> <span class="nv">$count</span> <span class="p">);</span>
<span class="k">my</span> <span class="nv">@comp</span>  <span class="o">=</span> <span class="mi">1</span> <span class="o">..</span> <span class="nv">$count</span><span class="p">;</span>
<span class="k">my</span> <span class="nv">%array</span> <span class="o">=</span> <span class="nb">map</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">=&gt;</span> <span class="mi">1</span> <span class="p">}</span> <span class="nv">@array</span><span class="p">;</span>
<span class="k">my</span> <span class="nv">%is_in_list</span><span class="p">;</span>
<span class="k">for</span> <span class="k">my</span> <span class="nv">$i</span> <span class="p">(</span><span class="nv">@comp</span><span class="p">)</span> <span class="p">{</span>
    <span class="nv">$is_in_list</span><span class="p">{</span><span class="nv">$i</span><span class="p">}</span> <span class="o">=</span>
        <span class="nb">defined</span> <span class="nv">$array</span><span class="p">[</span><span class="nv">$i</span><span class="p">]</span> <span class="p">?</span> <span class="p">'</span><span class="s1">true</span><span class="p">'</span> <span class="p">:</span> <span class="p">'</span><span class="s1">false</span><span class="p">';</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="the-results">The Results</h2>

<h3 id="checking-a-1000-element-list-1000-element-using-wallclock-seconds">Checking a 1,000-element list (1,000-element) using wallclock seconds</h3>

<table>
  <thead>
    <tr>
      <th>checking <em>n</em> values</th>
      <th>First</th>
      <th>Grep</th>
      <th>Hash</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>5</td>
      <td>1</td>
      <td>2</td>
      <td>5</td>
    </tr>
    <tr>
      <td>50</td>
      <td>6</td>
      <td>11</td>
      <td>5</td>
    </tr>
    <tr>
      <td>500</td>
      <td>46</td>
      <td>97</td>
      <td>5</td>
    </tr>
  </tbody>
</table>

<p>Benchmark warned that these few elements might be unrepresentative, so let’s look at the next one.</p>

<h3 id="checking-a-10000-element-list-10000-element-array-using-wallclock-seconds">Checking a 10,000-element list (10,000-element array) using wallclock seconds</h3>

<table>
  <thead>
    <tr>
      <th>checking <em>n</em> values</th>
      <th>First</th>
      <th>Grep</th>
      <th>Hash</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>5</td>
      <td>13</td>
      <td>19</td>
      <td>103</td>
    </tr>
    <tr>
      <td>50</td>
      <td>150</td>
      <td>257</td>
      <td>80</td>
    </tr>
    <tr>
      <td>500</td>
      <td>1045</td>
      <td>1887</td>
      <td>57</td>
    </tr>
  </tbody>
</table>

<p>And a chart generated in Google Sheets:</p>

<p><img src="https://jacoby.github.io/images/first_grep_hash_best_graph.png" alt="Chart visualizing the above data" /></p>

<p>The value stored for these charts is using wallclock seconds, so, for the time to see which elements are in the array using <strong>Grep</strong> to check for 500 values took <strong>1887 seconds</strong>, which <strong>is over a half hour</strong>., while again, while the <strong>Hash</strong> version is, within the context of the same array, essentially constant, while the other are exponential.</p>

<h2 id="conclusion">Conclusion</h2>

<p>The larger the list you’re working with, the better it is to keep track of list membership if that’s a thing you need, but for smaller lists, it would be better to use <strong>Any</strong> or <strong>First</strong> or <strong>Grep</strong>.</p>

<p>But data size explodes, so planning ahead might be smart, making <strong>Hash</strong> a valid choice for small arrays and the best choice for bigger ones.</p>

<p>Which vindicates my choices, which feels good.</p>

<h2 id="code-and-data">Code and Data</h2>

<h3 id="data">Data</h3>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>========================
count:  400
array:  1000
comp:   5

Benchmark: timing 400 iterations of First, Grep, Hash...
     First:  1 wallclock secs ( 0.33 usr +  0.00 sys =  0.33 CPU) @ 1212.12/s (n=400)
            (warning: too few iterations for a reliable count)
      Grep:  2 wallclock secs ( 1.08 usr +  0.03 sys =  1.11 CPU) @ 360.36/s (n=400)
      Hash:  5 wallclock secs ( 1.95 usr +  0.00 sys =  1.95 CPU) @ 205.13/s (n=400)
========================
count:  400
array:  1000
comp:   50

Benchmark: timing 400 iterations of First, Grep, Hash...
     First:  6 wallclock secs ( 2.26 usr +  0.00 sys =  2.26 CPU) @ 176.99/s (n=400)
      Grep: 11 wallclock secs ( 4.57 usr +  0.02 sys =  4.59 CPU) @ 87.15/s (n=400)
      Hash:  5 wallclock secs ( 1.36 usr +  0.00 sys =  1.36 CPU) @ 294.12/s (n=400)
========================
count:  400
array:  1000
comp:   500

Benchmark: timing 400 iterations of First, Grep, Hash...
     First: 46 wallclock secs (17.81 usr +  0.11 sys = 17.92 CPU) @ 22.32/s (n=400)
      Grep: 97 wallclock secs (43.08 usr +  0.12 sys = 43.20 CPU) @  9.26/s (n=400)
      Hash:  5 wallclock secs ( 1.70 usr +  0.05 sys =  1.75 CPU) @ 228.57/s (n=400)
========================
count:  400
array:  10000
comp:   5

Benchmark: timing 400 iterations of First, Grep, Hash...
     First: 13 wallclock secs ( 4.03 usr +  0.03 sys =  4.06 CPU) @ 98.52/s (n=400)
      Grep: 19 wallclock secs ( 6.51 usr +  0.03 sys =  6.54 CPU) @ 61.16/s (n=400)
      Hash: 103 wallclock secs (43.47 usr +  0.28 sys = 43.75 CPU) @  9.14/s (n=400)
========================
count:  400
array:  10000
comp:   50

Benchmark: timing 400 iterations of First, Grep, Hash...
     First: 150 wallclock secs (55.47 usr +  0.25 sys = 55.72 CPU) @  7.18/s (n=400)
      Grep: 257 wallclock secs (105.11 usr +  0.28 sys = 105.39 CPU) @  3.80/s (n=400)
      Hash: 80 wallclock secs (30.44 usr +  0.25 sys = 30.69 CPU) @ 13.03/s (n=400)
========================
count:  400
array:  10000
comp:   500

Benchmark: timing 400 iterations of First, Grep, Hash...
     First: 1045 wallclock secs (448.34 usr +  1.36 sys = 449.70 CPU) @  0.89/s (n=400)
      Grep: 1887 wallclock secs (837.35 usr +  2.70 sys = 840.05 CPU) @  0.48/s (n=400)
      Hash: 57 wallclock secs (30.45 usr +  0.06 sys = 30.51 CPU) @ 13.11/s (n=400)
========================
count:  400
array:  100000
comp:   5

Benchmark: timing 400 iterations of First, Grep, Hash...
     First: 117 wallclock secs (55.00 usr +  0.27 sys = 55.27 CPU) @  7.24/s (n=400)
      Grep: 176 wallclock secs (75.20 usr +  0.41 sys = 75.61 CPU) @  5.29/s (n=400)
      Hash: 899 wallclock secs (379.11 usr +  1.31 sys = 380.42 CPU) @  1.05/s (n=400)

</code></pre></div></div>

<h3 id="code">Code</h3>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env perl</span>

<span class="c1"># elements_in_list.pl</span>

<span class="k">use</span> <span class="nv">strict</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">warnings</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">experimental</span> <span class="sx">qw{ say signatures state fc }</span><span class="p">;</span>

<span class="k">use</span> <span class="nv">Benchmark</span>  <span class="sx">qw{ :all }</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">List::</span><span class="nv">Util</span> <span class="sx">qw{ first }</span><span class="p">;</span>

<span class="c1"># originally wrote this to switch between</span>
<span class="c1"># different iteration counts and different</span>
<span class="c1"># array sizes, but the sweet spot for</span>
<span class="c1"># learing is 400 iterations and an array of</span>
<span class="c1"># 10,000 elements.</span>

<span class="k">for</span> <span class="k">my</span> <span class="nv">$count</span> <span class="p">(</span><span class="sx">qw{ 400 }</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="k">my</span> <span class="nv">$array</span> <span class="p">(</span><span class="sx">qw{ 10000 }</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="k">my</span> <span class="nv">$comp</span> <span class="p">(</span><span class="sx">qw{ 5 50 500 }</span><span class="p">)</span> <span class="p">{</span>
            <span class="nv">say</span> <span class="o">&lt;&lt;~</span><span class="p">"</span><span class="s2">END</span><span class="p">";</span>
                <span class="o">========================</span>
                <span class="nv">count:</span>  <span class="nv">$count</span>
                <span class="nv">array:</span>  <span class="nv">$array</span>
                <span class="nv">comp:</span>   <span class="nv">$comp</span>
                <span class="k">END</span>

            <span class="nv">timethese</span><span class="p">(</span>
                <span class="nv">$count</span><span class="p">,</span>
                <span class="p">{</span>
                    <span class="p">'</span><span class="s1">First</span><span class="p">'</span> <span class="o">=&gt;</span> <span class="k">sub </span><span class="p">{</span>
                        <span class="k">my</span> <span class="nv">@array</span> <span class="o">=</span> <span class="nb">map</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">*</span> <span class="mi">2</span> <span class="p">}</span> <span class="mi">0</span> <span class="o">..</span> <span class="p">(</span> <span class="mi">10</span> <span class="o">*</span> <span class="nv">$array</span> <span class="p">);</span>
                        <span class="k">my</span> <span class="nv">@comp</span>  <span class="o">=</span> <span class="mi">1</span> <span class="o">..</span> <span class="nv">$comp</span><span class="p">;</span>
                        <span class="k">my</span> <span class="nv">%is_in_list</span><span class="p">;</span>
                        <span class="k">for</span> <span class="k">my</span> <span class="nv">$i</span> <span class="p">(</span><span class="nv">@comp</span><span class="p">)</span> <span class="p">{</span>
                            <span class="nb">no</span> <span class="nv">warnings</span><span class="p">;</span>
                            <span class="k">my</span> <span class="nv">$first</span> <span class="o">=</span> <span class="nv">first</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">==</span> <span class="nv">$i</span> <span class="p">}</span> <span class="nv">@array</span><span class="p">;</span>
                            <span class="nv">$is_in_list</span><span class="p">{</span><span class="nv">$i</span><span class="p">}</span> <span class="o">=</span>
                                <span class="nb">defined</span> <span class="nv">$first</span> <span class="p">?</span> <span class="p">'</span><span class="s1">true</span><span class="p">'</span> <span class="p">:</span> <span class="p">'</span><span class="s1">false</span><span class="p">';</span>
                        <span class="p">}</span>
                    <span class="p">},</span>
                    <span class="p">'</span><span class="s1">Grep</span><span class="p">'</span> <span class="o">=&gt;</span> <span class="k">sub </span><span class="p">{</span>
                        <span class="k">my</span> <span class="nv">@array</span> <span class="o">=</span> <span class="nb">map</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">*</span> <span class="mi">2</span> <span class="p">}</span> <span class="mi">0</span> <span class="o">..</span> <span class="p">(</span> <span class="mi">10</span> <span class="o">*</span> <span class="nv">$array</span> <span class="p">);</span>
                        <span class="k">my</span> <span class="nv">@comp</span>  <span class="o">=</span> <span class="mi">1</span> <span class="o">..</span> <span class="nv">$comp</span><span class="p">;</span>
                        <span class="k">my</span> <span class="nv">%is_in_list</span><span class="p">;</span>
                        <span class="k">for</span> <span class="k">my</span> <span class="nv">$i</span> <span class="p">(</span><span class="nv">@comp</span><span class="p">)</span> <span class="p">{</span>
                            <span class="nv">$is_in_list</span><span class="p">{</span><span class="nv">$i</span><span class="p">}</span> <span class="o">=</span>
                                <span class="p">(</span> <span class="nb">grep</span> <span class="p">{</span> <span class="nv">$i</span> <span class="o">==</span> <span class="vg">$_</span> <span class="p">}</span> <span class="nv">@array</span> <span class="p">)</span>
                                <span class="p">?</span> <span class="p">'</span><span class="s1">true</span><span class="p">'</span>
                                <span class="p">:</span> <span class="p">'</span><span class="s1">false</span><span class="p">';</span>
                        <span class="p">}</span>
                    <span class="p">},</span>
                    <span class="p">'</span><span class="s1">Hash</span><span class="p">'</span> <span class="o">=&gt;</span> <span class="k">sub </span><span class="p">{</span>
                        <span class="k">my</span> <span class="nv">@array</span> <span class="o">=</span> <span class="nb">map</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">*</span> <span class="mi">2</span> <span class="p">}</span> <span class="mi">0</span> <span class="o">..</span> <span class="p">(</span> <span class="mi">10</span> <span class="o">*</span> <span class="nv">$array</span> <span class="p">);</span>
                        <span class="k">my</span> <span class="nv">@comp</span>  <span class="o">=</span> <span class="mi">1</span> <span class="o">..</span> <span class="nv">$comp</span><span class="p">;</span>
                        <span class="k">my</span> <span class="nv">%array</span> <span class="o">=</span> <span class="nb">map</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">=&gt;</span> <span class="mi">1</span> <span class="p">}</span> <span class="nv">@array</span><span class="p">;</span>
                        <span class="k">my</span> <span class="nv">%is_in_list</span><span class="p">;</span>
                        <span class="k">for</span> <span class="k">my</span> <span class="nv">$i</span> <span class="p">(</span><span class="nv">@comp</span><span class="p">)</span> <span class="p">{</span>
                            <span class="nv">$is_in_list</span><span class="p">{</span><span class="nv">$i</span><span class="p">}</span> <span class="o">=</span>
                                <span class="nb">defined</span> <span class="nv">$array</span><span class="p">[</span><span class="nv">$i</span><span class="p">]</span> <span class="p">?</span> <span class="p">'</span><span class="s1">true</span><span class="p">'</span> <span class="p">:</span> <span class="p">'</span><span class="s1">false</span><span class="p">';</span>
                        <span class="p">}</span>
                    <span class="p">},</span>
                <span class="p">}</span>
            <span class="p">);</span>

        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
<span class="nb">exit</span><span class="p">;</span>

</code></pre></div></div>

<h4 id="if-you-have-any-questions-or-comments-i-would-be-glad-to-hear-it-ask-me-on-mastodon-or-make-an-issue-on-my-blog-repo">If you have any questions or comments, I would be glad to hear it. Ask me on <a href="https://mastodon.xyz/@jacobydave">Mastodon</a> or <a href="https://github.com/jacoby/jacoby.github.io">make an issue on my blog repo.</a></h4>]]></content><author><name>Dave Jacoby</name></author><summary type="html"><![CDATA[This starts with comparative programming. I had reason to code some Python recently, and I discovered that there was a built-in to tell if an element is in a list.]]></summary></entry><entry><title type="html">No Mental Bandwidth For A Name: Weekly Challenge #258</title><link href="https://jacoby.github.io//2024/02/26/no-mental-bandwidth-for-a-name-weekly-challenge-258.html" rel="alternate" type="text/html" title="No Mental Bandwidth For A Name: Weekly Challenge #258" /><published>2024-02-26T16:15:38+00:00</published><updated>2024-02-26T16:15:38+00:00</updated><id>https://jacoby.github.io//2024/02/26/no-mental-bandwidth-for-a-name-weekly-challenge-258</id><content type="html" xml:base="https://jacoby.github.io//2024/02/26/no-mental-bandwidth-for-a-name-weekly-challenge-258.html"><![CDATA[<p><a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-258/"><strong>Welcome to Weekly Challenge #258!</strong></a></p>

<p>I’m working on a lot of things and can’t work up the creativity to come up with the facts about <strong>258</strong> today. Incidentally, if you’re looking for an experience Perl guy, ways to contact me are listed below.</p>

<h3 id="task-1-count-even-digits-number">Task 1: Count Even Digits Number</h3>

<blockquote>
  <p>Submitted by: Mohammad Sajid Anwar
You are given a array of positive integers, @ints.</p>

  <p>Write a script to find out how many integers have even number of digits.</p>
</blockquote>

<h4 id="lets-talk-about-it">Let’s Talk About It</h4>

<p>I wasn’t trying to “victory lap” this one, really, but on first glance, I had this.</p>

<p>Perl variables are simultaneously strings and numbers. We use variable overloading, not operator overloading, so if you do a math thing on a string, Perl will find the most number-y take on that variable, and if you do a string thing, it’ll treat it as such.</p>

<p>If you want to find the length of a string, use <code class="language-plaintext highlighter-rouge">length</code>.</p>

<p>If you want to find an even number, use modulus, or <code class="language-plaintext highlighter-rouge">%</code>.</p>

<p>If you want to only pass only the number with an even number of digits, use <code class="language-plaintext highlighter-rouge">grep { ( length $_ ) % 2 == 0 }</code>. The parentheses are important because otherwise, it’ll try to get the length of <code class="language-plaintext highlighter-rouge">$_ % 2 </code>.</p>

<p>If you want to find the length of an array, use <code class="language-plaintext highlighter-rouge">scalar</code>.</p>

<p>So, <code class="language-plaintext highlighter-rouge">scalar grep { ( length $_ ) % 2 == 0 }</code>. You could probably golf that down a lot, but to me, this is the minimal readable size of this solution.</p>

<h4 id="show-me-the-code">Show Me The Code!</h4>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env perl</span>

<span class="k">use</span> <span class="nv">strict</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">warnings</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">experimental</span> <span class="sx">qw{ say postderef signatures state }</span><span class="p">;</span>

<span class="k">my</span> <span class="nv">@examples</span> <span class="o">=</span> <span class="p">(</span>

    <span class="p">[</span> <span class="mi">10</span><span class="p">,</span>  <span class="mi">1</span><span class="p">,</span> <span class="mi">111</span><span class="p">,</span> <span class="mi">24</span><span class="p">,</span> <span class="mi">1000</span> <span class="p">],</span>
    <span class="p">[</span> <span class="mi">111</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">11111</span> <span class="p">],</span>
    <span class="p">[</span> <span class="mi">2</span><span class="p">,</span>   <span class="mi">8</span><span class="p">,</span> <span class="mi">1024</span><span class="p">,</span> <span class="mi">256</span> <span class="p">],</span>
<span class="p">);</span>

<span class="k">for</span> <span class="k">my</span> <span class="nv">$example</span> <span class="p">(</span><span class="nv">@examples</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">my</span> <span class="nv">$output</span> <span class="o">=</span> <span class="nb">scalar</span> <span class="nb">grep</span> <span class="p">{</span> <span class="p">(</span> <span class="nb">length</span> <span class="vg">$_</span> <span class="p">)</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">}</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="nv">@*</span><span class="p">;</span>
    <span class="k">my</span> <span class="nv">$ints</span>   <span class="o">=</span> <span class="nb">join</span> <span class="p">'</span><span class="s1">, </span><span class="p">',</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="nv">@*</span><span class="p">;</span>

    <span class="nv">say</span> <span class="o">&lt;&lt;~</span><span class="p">"</span><span class="s2">END</span><span class="p">";</span>
    <span class="nv">Input:</span>  <span class="o">\</span><span class="nv">@ints</span> <span class="o">=</span> <span class="p">(</span><span class="nv">$ints</span><span class="p">)</span>
    <span class="nv">Output:</span> <span class="nv">$output</span>
    <span class="k">END</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ./ch-1.pl 
Input:  @ints = (10, 1, 111, 24, 1000)
Output: 3

Input:  @ints = (111, 1, 11111)
Output: 0

Input:  @ints = (2, 8, 1024, 256)
Output: 1
</code></pre></div></div>

<h3 id="task-2-sum-of-values">Task 2: Sum of Values</h3>

<blockquote>
  <p>Submitted by: Mohammad Sajid Anwar
You are given an array of integers, @int and an integer $k.</p>

  <p>Write a script to find the sum of values whose index binary representation has exactly $k number of 1-bit set.</p>
</blockquote>

<h4 id="lets-talk-about-it-1">Let’s Talk About It</h4>

<p>I use <code class="language-plaintext highlighter-rouge">sprintf</code> a fair amount, as an easy way to left-pad numbers and a way to cut long floating point numbers to a more usable set of significant digits, but it also, with <code class="language-plaintext highlighter-rouge">'%b'</code>, converts a number to binary.</p>

<p><code class="language-plaintext highlighter-rouge">split //</code> splits between every character, so combining them turns <code class="language-plaintext highlighter-rouge">5</code> into <code class="language-plaintext highlighter-rouge">[1,0,1]</code>.</p>

<p><a href="https://metacpan.org/pod/List::Util">List::Util</a> has <code class="language-plaintext highlighter-rouge">sum0</code>, but I suppose I could’ve nodded to the previous task and written <code class="language-plaintext highlighter-rouge">scalar grep { $_ == 1 }</code> instead. Alas.</p>

<p>I could do it in a more functional way. I actually wrote it.</p>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">return</span> <span class="nv">sum0</span> <span class="nb">map</span> <span class="p">{</span> <span class="vg">$_</span><span class="o">-&gt;</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="p">}</span>
        <span class="nb">grep</span> <span class="p">{</span> <span class="vg">$_</span><span class="o">-&gt;</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="nv">$k</span> <span class="p">}</span>
        <span class="nb">map</span> <span class="p">{</span> <span class="p">[</span> <span class="vg">$_</span><span class="p">,</span> <span class="nv">$ints</span><span class="p">[</span><span class="vg">$_</span><span class="p">],</span> <span class="nv">sum0</span> <span class="nb">split</span> <span class="sr">//</span><span class="p">,</span> <span class="nb">sprintf</span> <span class="p">'</span><span class="s1">%b</span><span class="p">',</span> <span class="vg">$_</span> <span class="p">]</span> <span class="p">}</span> <span class="mi">0</span> <span class="o">..</span> <span class="nv">$#ints</span><span class="p">;</span>
</code></pre></div></div>

<p>But that’s about the size of the iterative version, and it’s much less readable to me.</p>

<h4 id="show-me-the-code-1">Show Me The Code!</h4>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env perl</span>

<span class="k">use</span> <span class="nv">strict</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">warnings</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">experimental</span> <span class="sx">qw{ say postderef signatures state }</span><span class="p">;</span>

<span class="k">use</span> <span class="nn">List::</span><span class="nv">Util</span> <span class="sx">qw{ sum0 }</span><span class="p">;</span>

<span class="k">my</span> <span class="nv">@examples</span> <span class="o">=</span> <span class="p">(</span>

    <span class="p">{</span>
        <span class="s">ints</span> <span class="o">=&gt;</span> <span class="p">[</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">3</span> <span class="p">],</span>
        <span class="s">k</span>    <span class="o">=&gt;</span> <span class="mi">1</span>
    <span class="p">},</span>
    <span class="p">{</span>
        <span class="s">ints</span> <span class="o">=&gt;</span> <span class="p">[</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">3</span> <span class="p">],</span>
        <span class="s">k</span>    <span class="o">=&gt;</span> <span class="mi">2</span>
    <span class="p">},</span>
    <span class="p">{</span>
        <span class="s">ints</span> <span class="o">=&gt;</span> <span class="p">[</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">3</span> <span class="p">],</span>
        <span class="s">k</span>    <span class="o">=&gt;</span> <span class="mi">0</span>
    <span class="p">}</span>
<span class="p">);</span>

<span class="k">for</span> <span class="k">my</span> <span class="nv">$example</span> <span class="p">(</span><span class="nv">@examples</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">my</span> <span class="nv">@output</span> <span class="o">=</span> <span class="nv">sum_of_values</span><span class="p">(</span><span class="nv">$example</span><span class="p">);</span>
    <span class="k">my</span> <span class="nv">$ints</span>   <span class="o">=</span> <span class="nb">join</span> <span class="p">'</span><span class="s1">, </span><span class="p">',</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="p">{</span><span class="nv">ints</span><span class="p">}</span><span class="o">-&gt;</span><span class="nv">@*</span><span class="p">;</span>
    <span class="k">my</span> <span class="nv">$k</span>      <span class="o">=</span> <span class="nb">join</span> <span class="p">'</span><span class="s1">, </span><span class="p">',</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="p">{</span><span class="nv">k</span><span class="p">};</span>
    <span class="k">my</span> <span class="nv">$output</span> <span class="o">=</span> <span class="nb">join</span> <span class="p">'</span><span class="s1">, </span><span class="p">',</span> <span class="nv">@output</span><span class="p">;</span>

    <span class="nv">say</span> <span class="o">&lt;&lt;~</span><span class="p">"</span><span class="s2">END</span><span class="p">";</span>
    <span class="nv">Input:</span>  <span class="o">\</span><span class="nv">@ints</span> <span class="o">=</span> <span class="p">(</span><span class="nv">$ints</span><span class="p">),</span> <span class="o">\</span><span class="nv">$k</span> <span class="o">=</span> <span class="nv">$k</span>
    <span class="nv">Output:</span> <span class="nv">$output</span>
    <span class="k">END</span>
<span class="p">}</span>

<span class="k">sub </span><span class="nf">sum_of_values</span> <span class="p">($obj) {</span>
    <span class="k">my</span> <span class="nv">@ints</span>   <span class="o">=</span> <span class="nv">$obj</span><span class="o">-&gt;</span><span class="p">{</span><span class="nv">ints</span><span class="p">}</span><span class="o">-&gt;</span><span class="nv">@*</span><span class="p">;</span>
    <span class="k">my</span> <span class="nv">$k</span>      <span class="o">=</span> <span class="nv">$obj</span><span class="o">-&gt;</span><span class="p">{</span><span class="nv">k</span><span class="p">};</span>
    <span class="k">my</span> <span class="nv">$output</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="k">for</span> <span class="k">my</span> <span class="nv">$i</span> <span class="p">(</span> <span class="mi">0</span> <span class="o">..</span> <span class="nv">$#ints</span> <span class="p">)</span> <span class="p">{</span>
        <span class="k">my</span> <span class="nv">$s</span> <span class="o">=</span> <span class="nv">sum0</span> <span class="nb">split</span> <span class="sr">//</span><span class="p">,</span> <span class="nb">sprintf</span> <span class="p">'</span><span class="s1">%b</span><span class="p">',</span> <span class="nv">$i</span><span class="p">;</span>
        <span class="nv">$output</span> <span class="o">+=</span> <span class="nv">$ints</span><span class="p">[</span><span class="nv">$i</span><span class="p">]</span> <span class="k">if</span> <span class="nv">$s</span> <span class="o">==</span> <span class="nv">$k</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nv">$output</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ./ch-2.pl 
Input:  @ints = (2, 5, 9, 11, 3), $k = 1
Output: 17

Input:  @ints = (2, 5, 9, 11, 3), $k = 2
Output: 11

Input:  @ints = (2, 5, 9, 11, 3), $k = 0
Output: 2
</code></pre></div></div>

<h4 id="if-you-have-any-questions-or-comments-i-would-be-glad-to-hear-it-ask-me-on-mastodon-or-make-an-issue-on-my-blog-repo">If you have any questions or comments, I would be glad to hear it. Ask me on <a href="https://mastodon.xyz/@jacobydave">Mastodon</a> or <a href="https://github.com/jacoby/jacoby.github.io">make an issue on my blog repo.</a></h4>]]></content><author><name>Dave Jacoby</name></author><summary type="html"><![CDATA[Welcome to Weekly Challenge #258!]]></summary></entry><entry><title type="html">Note To Self on PAUSE Workflow</title><link href="https://jacoby.github.io//2024/02/24/note-to-self-on-pause-workflow.html" rel="alternate" type="text/html" title="Note To Self on PAUSE Workflow" /><published>2024-02-24T21:25:41+00:00</published><updated>2024-02-24T21:25:41+00:00</updated><id>https://jacoby.github.io//2024/02/24/note-to-self-on-pause-workflow</id><content type="html" xml:base="https://jacoby.github.io//2024/02/24/note-to-self-on-pause-workflow.html"><![CDATA[<p>gizmomathboy told me to write a note, because I hadn’t touched this process for years. This is me writing that note.</p>

<p>For a lot of modules, they have a Makefile. Even if they don’t have anything to compile.</p>

<p>The trick there is with <code class="language-plaintext highlighter-rouge">make dist</code>, which creates a distribution. And, in terms of PAUSE, the way that modules enter CPAN, a dist is a distribution, which is a file taking the form <code class="language-plaintext highlighter-rouge">$MODULE_NAME-$VERSION_NUMBER.tar.gz</code>, which of course you could make yourself, but by using a makefile, you consistently do the right thing.</p>

<p>Then, you log into PAUSE and upload it. There are means to add this to your GitHub Actions, which I <em>might</em> do for some projects. The thing that hits me is that unless <code class="language-plaintext highlighter-rouge">$VERSION_NUMBER</code> changes, and changes up, PAUSE doesn’t do anything with it. Does it make it “safe” and “okay” to make a bunch of builds when you’re just adding testing?</p>

<p>Anyway, note to self.</p>

<h4 id="if-you-have-any-questions-or-comments-i-would-be-glad-to-hear-it-ask-me-on-mastodon-or-make-an-issue-on-my-blog-repo">If you have any questions or comments, I would be glad to hear it. Ask me on <a href="https://mastodon.xyz/@jacobydave">Mastodon</a> or <a href="https://github.com/jacoby/jacoby.github.io">make an issue on my blog repo.</a></h4>]]></content><author><name>Dave Jacoby</name></author><summary type="html"><![CDATA[gizmomathboy told me to write a note, because I hadn’t touched this process for years. This is me writing that note.]]></summary></entry><entry><title type="html">A few quick notes on GitHub Actions</title><link href="https://jacoby.github.io//2024/02/23/a-few-quick-notes-on-github-actions.html" rel="alternate" type="text/html" title="A few quick notes on GitHub Actions" /><published>2024-02-23T20:20:17+00:00</published><updated>2024-02-23T20:20:17+00:00</updated><id>https://jacoby.github.io//2024/02/23/a-few-quick-notes-on-github-actions</id><content type="html" xml:base="https://jacoby.github.io//2024/02/23/a-few-quick-notes-on-github-actions.html"><![CDATA[<p>I avoided looking at GitHub Actions for a long time. I had set some automation on a few things with <a href="https://www.appveyor.com/">Appveyor</a> and <a href="https://www.travis-ci.com/">TravisCI</a>, but the things I was coding were for work and not using GitHub, and the things I had added automation to were stable. I doubt I’ve done anything with some of the repos but test the testing. 🤓</p>

<p>But I’m told it’s good for me, and here I am, adding to something I’ve successfully run tests on before, on both services.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">run perl ubuntu</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="na">push</span><span class="pi">:</span>
    <span class="na">branches</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">*"</span>
  <span class="na">pull_request</span><span class="pi">:</span>
    <span class="na">branches</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">*"</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">perl-job</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">strategy</span><span class="pi">:</span>
      <span class="na">fail-fast</span><span class="pi">:</span> <span class="no">false</span>
      <span class="na">matrix</span><span class="pi">:</span>
        <span class="na">perl-version</span><span class="pi">:</span>
          <span class="pi">[</span>
            <span class="s2">"</span><span class="s">5.38"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.36"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.34"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.32"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.30"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.28"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.26"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.24"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.22"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.20"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.18"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.16"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.14"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.12"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.10"</span><span class="pi">,</span>
            <span class="s2">"</span><span class="s">5.8"</span><span class="pi">,</span>
          <span class="pi">]</span>
    <span class="na">container</span><span class="pi">:</span>
      <span class="na">image</span><span class="pi">:</span> <span class="s">perldocker/perl-tester:$</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v2</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Regular tests</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">cpanm --notest Test::Builder Test::More IO::Pty IO::Tty</span>
          <span class="s">cpanm --installdeps --notest . </span>
          <span class="s">perl Makefile.PL</span>
          <span class="s">make </span>
          <span class="s">make test</span>
</code></pre></div></div>

<p>I’m hardcoding the dependencies and test modules in the first line of my <code class="language-plaintext highlighter-rouge">run</code> above. In the fullness of time, I might pull those and see what’s going on. I think I know the problem that I was having that made me want to pull them, and that wasn’t about dependencies.</p>

<p>I am jazzed that I can test this module as far back as 5.8. I had tested to 5.10 on Travis before, so when I was getting the <code class="language-plaintext highlighter-rouge">perl-version</code> thing going, I decided to go as far back as I deemed even vaguely reasonable. Thanks to <a href="https://hub.docker.com/u/perldocker">perldocker on DockerHub</a>, create by <a href="https://www.perlfoundation.org/">the Perl and Raku Foundation</a>.</p>

<p>Also thanks to <a href="https://perlmaven.com/">Gabor Szabo’s PerlMaven</a> and <a href="https://perlmaven.com/setup-github-actions">the five-year-old GitHub Action examples I’m heavily cribbing from</a>.</p>

<p>I think I’ll only be able to test on MacOS against <code class="language-plaintext highlighter-rouge">macos-latest</code> and the Perl it provides, but that’s fine.</p>

<p>But, while I had this going, I jumped to the Appveyor Windows-specific script, and found that it was trying to do <code class="language-plaintext highlighter-rouge">MSBuild</code> on it, like through Visual Studio, and that’s not necessary.</p>

<p>(It makes no sense to get a tool or service working again when I’m planning to replace them, but it makes me feel like I’m accomplishing a thing.)</p>

<p>But once that was fixed, I found another error. cpanm couldn’t build a dependency, but the build log was on the far side of the service, so I tried locally, and saw this in the build log.</p>

<blockquote>
  <p><code class="language-plaintext highlighter-rouge">OS unsupported at Makefile.PL line 6.</code></p>
</blockquote>

<p>IO::Tty doesn’t even try to build on Windows. So whatever positive tests I got years ago were false positives, and my choices are to live with it or make IO::Tty work with <a href="https://strawberryperl.com/">Strawberry Perl</a>.</p>

<p>So I have <em>that</em> going forme.</p>

<h4 id="if-you-have-any-questions-or-comments-i-would-be-glad-to-hear-it-ask-me-on-mastodon-or-make-an-issue-on-my-blog-repo">If you have any questions or comments, I would be glad to hear it. Ask me on <a href="https://mastodon.xyz/@jacobydave">Mastodon</a> or <a href="https://github.com/jacoby/jacoby.github.io">make an issue on my blog repo.</a></h4>]]></content><author><name>Dave Jacoby</name></author><summary type="html"><![CDATA[I avoided looking at GitHub Actions for a long time. I had set some automation on a few things with Appveyor and TravisCI, but the things I was coding were for work and not using GitHub, and the things I had added automation to were stable. I doubt I’ve done anything with some of the repos but test the testing. 🤓]]></summary></entry><entry><title type="html">Trying GitLens</title><link href="https://jacoby.github.io//2024/02/23/trying-gitlens.html" rel="alternate" type="text/html" title="Trying GitLens" /><published>2024-02-23T15:46:35+00:00</published><updated>2024-02-23T15:46:35+00:00</updated><id>https://jacoby.github.io//2024/02/23/trying-gitlens</id><content type="html" xml:base="https://jacoby.github.io//2024/02/23/trying-gitlens.html"><![CDATA[<p>One of the things I noticed when doing my meandering HackLafayette talk about <a href="https://jacoby.github.io/2024/02/22/the-best-things-about-vs-code-today.html">VS Code</a> was <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens">GitLens</a>, which is an improvement on the existing Git implementation in VS Code.</p>

<p>Most of the time, for this blog, I write it in VSCode, with a Markdown Preview window opened in the right half of the editor window. If you see green in <a href="https://github.com/jacoby">my GitHub heatmap</a> these days, there’s a good chance that I’m committing and pushing with <a href="https://code.visualstudio.com/docs/sourcecontrol/overview">VS Code’s default Git integration</a>. It is good for commit and push, but often you want to understand the greater application, and honestly, this blog is all commits to master and pushes to origin.</p>

<p>I decided to clone down <a href="https://github.com/jacoby/RLangSyntax">RLangSyntax</a>, which provided syntax highlighting for <a href="https://www.activestate.com/products/komodo-edit/">ActiveState’s KomodoEdit</a>, my preferred editor after UltraEdit and before SublimeText. At that time, I was starting to do more R development, both for work and for personal projects, and KomodoEdit’s lack of R syntax highlighting annoyed me, so I found an existing abandoned project, copied it, put it on GitHub, added the GPL to the repo and explained old maintainer’s licensing in the README, and went forward.</p>

<p>Turns out, the core issue was that there’s an RDF file that the editor reads, and needed <code class="language-plaintext highlighter-rouge">em:targetApplication-&gt;Description-&gt;em:maxVersion</code> to be equal to or higher than the version number of the existing editor. I <em>suppose</em> I can understand not wanting to release it to editor versions that don’t exist yet, but if I had put an abstractly-large version number into the <code class="language-plaintext highlighter-rouge">maxVersion</code> fields, I wouldn’t need half the commits I made.</p>

<p>So, as I mentioned, I started developing in other editors, but when I noticed that KomodoEdit has a new version, I would update the application and make a new release.</p>

<p>Until 9.3, at least. That’s when I found that KomodoEdit 9 had R syntax highlighting and nobody needed this project anymore. I updated the README to say <strong>So Long And Thanks For The Fish</strong> and forgot about it.</p>

<p>I figured there’s just enough of a history that it would be worth looking at in GitLab, and the minimal outsider interaction would mean it’s okay to show. It’s my tent, it’s my clowns, so it’s my circus, so to speak.</p>

<p><img src="https://jacoby.github.io/images/vscode_gitlens.png" alt="GitLens ScreenShot" /></p>

<p>You can see several forks that got pulled into master from another user, this one fixing a misspelling that had slipped past me.</p>

<p>But the graph visualization, showing the tags that indicate points when I packaged for releases and the forks where Sergey cleaned up after me, is very interesting. I could definitely see value in this in projects with longer history, more users, and where I would be responsible for integrating pull requests into forks, forks into branches, and branches into production.</p>

<p>(Note to self, start using “production” instead of “master” for default branch, and look up other people’s best practices for branches.)</p>

<p>After a while of being unaware that another UI icon showed up in my editor and a little bit of distrust, I’m tentatively “that’s cool” about GitLens. Has anyone else tried it?</p>

<h4 id="if-you-have-any-questions-or-comments-i-would-be-glad-to-hear-it-ask-me-on-mastodon-or-make-an-issue-on-my-blog-repo">If you have any questions or comments, I would be glad to hear it. Ask me on <a href="https://mastodon.xyz/@jacobydave">Mastodon</a> or <a href="https://github.com/jacoby/jacoby.github.io">make an issue on my blog repo.</a></h4>]]></content><author><name>Dave Jacoby</name></author><summary type="html"><![CDATA[One of the things I noticed when doing my meandering HackLafayette talk about VS Code was GitLens, which is an improvement on the existing Git implementation in VS Code.]]></summary></entry><entry><title type="html">The Best Things About VS Code Today</title><link href="https://jacoby.github.io//2024/02/22/the-best-things-about-vs-code-today.html" rel="alternate" type="text/html" title="The Best Things About VS Code Today" /><published>2024-02-22T16:33:14+00:00</published><updated>2024-02-22T16:33:14+00:00</updated><id>https://jacoby.github.io//2024/02/22/the-best-things-about-vs-code-today</id><content type="html" xml:base="https://jacoby.github.io//2024/02/22/the-best-things-about-vs-code-today.html"><![CDATA[<p>I recently gave a presentation about VS Code to members of my local developer group, <a href="https://www.meetup.com/hacklafayette/">HackLafayette</a>. I worked through several bullet points in a fairly stream-of-consciousness and showed off a lot of how I use VS Code.</p>

<h2 id="remote-development">Remote Development</h2>

<p>I am a long-time user of <a href="https://code.visualstudio.com/">VS Code</a>. So long, <a href="https://jacoby.github.io/2018/09/19/i-find-the-strangest-bugs.html">I found a bug in VS Code in 2018</a>. At that time, I was working out of Ubuntu Linux and using <a href="https://www.digitalocean.com/community/tutorials/how-to-use-sshfs-to-mount-remote-file-systems-over-ssh">SSHFS</a> under <a href="https://www.kernel.org/doc/html/latest/filesystems/fuse.html">FUSE</a> to have the files and directories for research computing available to me on my local machine.</p>

<p>I did this almost entirely so I could open these files in VS Code, and opening these batch files from the command line was the bug.</p>

<p>If I was working in that position today, I would not need to do that, because today (and I am not sure how long this capability has existed), <a href="https://code.visualstudio.com/docs/remote/remote-overview">VS Code supports Remote Development</a>. I think it started so that people like me could code within their <a href="https://learn.microsoft.com/en-us/windows/wsl/">WSL</a> environments without having to jump through hoops like I had to in 2018.</p>

<p>Basically, there’s a separation between the frontend code and the backend, and they made it so that the communication between the two is abstracted. This means that the backend code can be set up and run invisibly to the user. With WSL, that communication doesn’t leave the computer, but <a href="https://code.visualstudio.com/blogs/2019/07/25/remote-ssh">VS Code is an SSH client that uses your .ssh/config</a>, so you can even use <a href="https://www.redhat.com/sysadmin/ssh-proxy-bastion-proxyjump">ProxyJump</a> to access machines not directly accessable.</p>

<p>This also means that you can <a href="https://code.visualstudio.com/docs/devcontainers/containers">use VS Code with Docker containers</a> and do Peer Programming remotely with <a href="https://code.visualstudio.com/learn/collaboration/live-share">Live Share</a>.</p>

<p>Additionally, <a href="https://code.visualstudio.com/docs/terminal/basics">VS Code has an integrated terminal</a>, so when you’re connected to the remote machine, you have a prompt there. At that time, I was working through <a href="https://aws.amazon.com/workspaces/">AWS Workspaces</a> on <a href="https://learn.microsoft.com/en-us/windows-server/get-started/editions-comparison-windows-server-2022?tabs=full-comparison">Window Server Datacenter</a>, which didn’t allow me to install MSI packages, meaning that I couldn’t use <a href="https://github.com/microsoft/terminal">Windows Terminal</a>, so VS Code ended up being the terminal I used almost all the time.</p>

<p>The terminal list is customizable, so if you want the ability to use <a href="https://www.nushell.sh/">Nushell</a> or Node or Python as a <a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">REPL</a>, that’s doable.</p>

<h2 id="workspaces-and-customization">Workspaces and Customization</h2>

<p>Early in my time with VS Code that when I opened up the editor, I got windows with a purple bar at the bottom.</p>

<p><img src="https://jacoby.github.io/images/vscode_window.png" alt="Default VS Code window" /></p>

<p>I was never in love with the color, and when, by accident, I opened things differently, I got a blue bar at the bottom.</p>

<p><img src="https://jacoby.github.io/images/vscode_workspace_window.png" alt="Default VS Code window" /></p>

<p>It took a while, and a discussion with <a href="https://genehack.org/">genehack</a> to understand that the second window is different because it is a <a href="https://code.visualstudio.com/docs/editor/workspaces">workspace</a>.</p>

<p>Workspaces mean that, when you close and open them again, the same files will be open. I believe the terminal history will also be retained.</p>

<p>They are also customizable. VS Code is very customizable, and those customizations are stored and are editable as JSON, but you can also specify customizations for workspaces. As an example, imagine you’re working on a group project outside your normal development, and there are differences, such as indent width, that are specific to that project.</p>

<p>In my talk, I created a workspace with the following settings. Several are definitely about display: changing font size and demonstrating ligatures in modern development fonts were part of what I wanted, but I will point out <code class="language-plaintext highlighter-rouge">terminal.integrated.defaultProfile.windows</code>. When I open a window in my default environment, it defaults to a bash shell in WSL, but here, I change that to <a href="https://learn.microsoft.com/en-us/powershell/">PowerShell</a>, which find bash-like enough for most shell purposes.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"editor.fontSize"</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span><span class="p">,</span><span class="w">
  </span><span class="nl">"editor.fontLigatures"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
  </span><span class="nl">"editor.renderWhitespace"</span><span class="p">:</span><span class="w"> </span><span class="s2">"boundary"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"editor.tabSize"</span><span class="p">:</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span><span class="w">
  </span><span class="nl">"editor.wrappingIndent"</span><span class="p">:</span><span class="w"> </span><span class="s2">"deepIndent"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"editor.defaultFormatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"bscan.perlnavigator"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"terminal.integrated.fontSize"</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span><span class="p">,</span><span class="w">
  </span><span class="nl">"terminal.integrated.defaultProfile.windows"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PowerShell"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>The customization also works with Remote Environments, so you can specify most anything for windows running over SSH. I commonly use different themes for different hosts, to help me to know where I am. Additionally, you can create and use different <a href="https://code.visualstudio.com/docs/editor/profiles">profiles</a>. Looking at the “Create New Profile” screen shows templates for Python, Angular, Doc Writer, Data Science, Node, and two Java-specific templates.</p>

<p>Also, within each context setting, you can specify things by language. Below is a subset of my default <code class="language-plaintext highlighter-rouge">settings.json</code>.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"[css]"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"editor.defaultFormatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"esbenp.prettier-vscode"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"[html]"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"editor.fontFamily"</span><span class="p">:</span><span class="w"> </span><span class="s2">"'Iosevka Term', 'Fantasque Sans Mono', Consolas, 'Courier New', monospace"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"editor.defaultFormatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"esbenp.prettier-vscode"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"[json]"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"editor.defaultFormatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"esbenp.prettier-vscode"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"editor.fontSize"</span><span class="p">:</span><span class="w"> </span><span class="mi">18</span><span class="p">,</span><span class="w">
    </span><span class="nl">"editor.fontFamily"</span><span class="p">:</span><span class="w"> </span><span class="s2">"'Iosevka Term', 'Fantasque Sans Mono', Consolas, 'Courier New', monospace"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"[jsonc]"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"editor.defaultFormatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"esbenp.prettier-vscode"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"editor.fontSize"</span><span class="p">:</span><span class="w"> </span><span class="mi">15</span><span class="p">,</span><span class="w">
    </span><span class="nl">"editor.fontFamily"</span><span class="p">:</span><span class="w"> </span><span class="s2">"'Iosevka Term', 'Fantasque Sans Mono', Consolas, 'Courier New', monospace"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"[javascript]"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"editor.defaultFormatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"esbenp.prettier-vscode"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"[markdown]"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"editor.defaultFormatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"esbenp.prettier-vscode"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"[perl]"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"editor.defaultFormatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"bscan.perlnavigator"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"[python]"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"editor.defaultFormatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ms-python.python"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"editor.formatOnType"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"[yaml]"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"editor.defaultFormatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"esbenp.prettier-vscode"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>These examples show mostly the font family, font size and default formatting engine for each language, but with Python, there’s <code class="language-plaintext highlighter-rouge">editor.formatOnType</code>, which formats the text while you write it. There are also options for <code class="language-plaintext highlighter-rouge">formatOnSave</code> and <code class="language-plaintext highlighter-rouge">formatOnPaste</code>, which start the formatting on other events.</p>

<p>So, VS Code can behave differently based on workspace, on environment, on profile and on language.</p>

<h2 id="extensions">Extensions</h2>

<p>And the custom behavior can involve functionality. So many of the language examples mention <a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode">Prettier</a>, a code formatter for Javascript, JSON, CSS, HTML, Markdown, YAML and a number of other languages. I mentioned that VS Code can work with <a href="https://www.docker.com/">Docker</a>, and that is done via <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker">the Docker extension</a>.</p>

<p>Using VS Code as an SSH client to connect to remote hosts comes from the <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh">Remote - SSH</a> extension, and there’s also <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.remote-explorer">Remote Explorer</a>, jumping directly to the workspaces on remote hosts.</p>

<p>There’s an extension I find powerful called <a href="https://marketplace.visualstudio.com/items?itemName=mechatroner.rainbow-csv">RainbowCSV</a>, which makes each column of a comma-separated file a different color, making them easier to read.</p>

<p>Not related to extensions, but VS Code is a Git client, so you can use it to connect to GitHub or Bitbucket directly, without the use of command-line Git tools or GitHub desktop. Most of the time, when I add to this blog, I write the markdown using the built-in Markdown Preview and commit and push from within VS Code. They’ve recently added <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens">GitLens</a>. I’ve barely touched it, but it seems like a useful tool for working with a large, long-lived repository with multiple contributors.</p>

<h2 id="end">End</h2>

<p>There is more to say about VS Code, about the formatters/linters and syntax highlighters that exist for most languages, extensions that allow you to treat VS Code like vim, debuggers and the like. Ultimately, the best thing about VS Code is the community, which creates tools to make it easier to do the things you need to do.</p>

<h4 id="if-you-have-any-questions-or-comments-i-would-be-glad-to-hear-it-ask-me-on-mastodon-or-make-an-issue-on-my-blog-repo">If you have any questions or comments, I would be glad to hear it. Ask me on <a href="https://mastodon.xyz/@jacobydave">Mastodon</a> or <a href="https://github.com/jacoby/jacoby.github.io">make an issue on my blog repo.</a></h4>]]></content><author><name>Dave Jacoby</name></author><summary type="html"><![CDATA[I recently gave a presentation about VS Code to members of my local developer group, HackLafayette. I worked through several bullet points in a fairly stream-of-consciousness and showed off a lot of how I use VS Code.]]></summary></entry><entry><title type="html">Lesser, Inferior, Lower, Junior: Weekly Challenge #257</title><link href="https://jacoby.github.io//2024/02/19/lesser-inferior-lower-junior-weekly-challenge-257.html" rel="alternate" type="text/html" title="Lesser, Inferior, Lower, Junior: Weekly Challenge #257" /><published>2024-02-19T18:17:44+00:00</published><updated>2024-02-19T18:17:44+00:00</updated><id>https://jacoby.github.io//2024/02/19/lesser-inferior-lower-junior-weekly-challenge-257</id><content type="html" xml:base="https://jacoby.github.io//2024/02/19/lesser-inferior-lower-junior-weekly-challenge-257.html"><![CDATA[<p>Welcome to <strong><a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-257/">Weekly Challenge #257</a>!</strong> [<strong>257</strong>(https://en.wikipedia.org/wiki/257<em>(number))] is a _prime number</em>, of the form <strong>2<sup>2<sup>n</sup></sup>+1</strong>. It is also an <a href="https://en.wikipedia.org/wiki/Regular_prime#Irregular_primes">irregular prime</a> and a <a href="https://en.wikipedia.org/wiki/Jacobsthal_number#Jacobsthal-Lucas_numbers">Jacobsthal-Lucas number</a>.</p>

<p><strong>257</strong> is the country code for <a href="https://en.wikipedia.org/wiki/Burundi">Burundi</a>, but is not currently assigned to the <a href="https://en.wikipedia.org/wiki/List_of_North_American_Numbering_Plan_area_codes">North American Numbering Plan</a>, but is scheduled to be assigned to British Columbia in 2025.</p>

<h3 id="task-1-smaller-than-current">Task 1: Smaller than Current</h3>

<blockquote>
  <p>Submitted by: Mohammad Sajid Anwar<br />
You are given a array of integers, <code class="language-plaintext highlighter-rouge">@ints</code>.</p>

  <p>Write a script to find out how many integers are smaller than current i.e. <code class="language-plaintext highlighter-rouge">foreach ints[i], count ints[j] &lt; ints[i] where i != j</code>.</p>
</blockquote>

<h4 id="lets-talk-about-it">Let’s Talk About it</h4>

<p>The key thought here is that we’re dealing with <em>less than</em>, not <em>less then or equal to</em>. I added code to remove the current value from the table, but any number <em>i</em> is not going to be less than itself, so <code class="language-plaintext highlighter-rouge">grep { $_ &lt; $i }</code> will always pass by <code class="language-plaintext highlighter-rouge">$_ == $i</code>. Easy to handle in a loop, but I wrote a very functional solution. Nested functional, in fact.</p>

<h4 id="show-me-the-code">Show Me The Code!</h4>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env perl</span>

<span class="k">use</span> <span class="nv">strict</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">warnings</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">experimental</span> <span class="sx">qw{ say postderef signatures state }</span><span class="p">;</span>

<span class="k">my</span> <span class="nv">@examples</span> <span class="o">=</span> <span class="p">(</span>

    <span class="p">[</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">6</span> <span class="p">],</span>
    <span class="p">[</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3</span> <span class="p">],</span>
    <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span> <span class="p">],</span>
    <span class="p">[</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">2</span> <span class="p">],</span>
<span class="p">);</span>

<span class="k">for</span> <span class="k">my</span> <span class="nv">$example</span> <span class="p">(</span><span class="nv">@examples</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">my</span> <span class="nv">@output</span> <span class="o">=</span> <span class="nv">smaller_than</span><span class="p">(</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="err">@</span><span class="o">*</span> <span class="p">);</span>
    <span class="k">my</span> <span class="nv">$input</span>  <span class="o">=</span> <span class="nb">join</span> <span class="p">'</span><span class="s1">, </span><span class="p">',</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="nv">@*</span><span class="p">;</span>
    <span class="k">my</span> <span class="nv">$output</span> <span class="o">=</span> <span class="nb">join</span> <span class="p">'</span><span class="s1">, </span><span class="p">',</span> <span class="nv">@output</span><span class="p">;</span>

    <span class="nv">say</span> <span class="o">&lt;&lt;~</span><span class="p">"</span><span class="s2">END</span><span class="p">";</span>
    <span class="nv">Input:</span>  <span class="o">\</span><span class="nv">@ints</span> <span class="o">=</span> <span class="p">(</span><span class="nv">$input</span><span class="p">)</span>
    <span class="nv">Output:</span> <span class="p">(</span><span class="nv">$output</span><span class="p">)</span>
    <span class="k">END</span>
<span class="p">}</span>

<span class="k">sub </span><span class="nf">smaller_than</span> <span class="p">(@ints) {</span>
    <span class="k">return</span> <span class="nb">map</span> <span class="p">{</span>
        <span class="k">my</span> <span class="nv">$i</span> <span class="o">=</span> <span class="vg">$_</span><span class="p">;</span>
        <span class="nb">scalar</span> <span class="nb">grep</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">&lt;</span> <span class="nv">$i</span> <span class="p">}</span> <span class="nv">@ints</span><span class="p">;</span>
    <span class="p">}</span> <span class="nv">@ints</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ./ch-1.pl
Input:  @ints = (5, 2, 1, 6)
Output: (2, 1, 0, 3)

Input:  @ints = (1, 2, 0, 3)
Output: (1, 2, 0, 3)

Input:  @ints = (0, 1)
Output: (0, 1)

Input:  @ints = (9, 4, 9, 2)
Output: (2, 1, 2, 0)
</code></pre></div></div>

<h3 id="task-2-reduced-row-echelon">Task 2: Reduced Row Echelon</h3>

<blockquote>
  <p>Submitted by: Ali Moradi<br />
Given a matrix M, check whether the matrix is in reduced row echelon form.</p>

  <p>A matrix must have the following properties to be in reduced row echelon form:</p>

  <ol>
    <li>If a row does not consist entirely of zeros, then the first nonzero number in the row is a 1. We call this the leading 1.</li>
    <li>If there are any rows that consist entirely of zeros, then they are grouped together at the bottom of the matrix.</li>
    <li>In any two successive rows that do not consist entirely of zeros, the leading 1 in the lower row occurs farther to the right than the leading 1 in the higher row.</li>
    <li>Each column that contains a leading 1 has zeros everywhere else in that column.</li>
  </ol>

  <p>For more information check out this <a href="https://en.wikipedia.org/wiki/Row_echelon_form">wikipedia article</a>.</p>
</blockquote>

<h4 id="lets-talk-about-it-1">Let’s Talk About it</h4>

<p><em>This</em> is the tough one.</p>

<p>Because we always want to display the matrices, I pulled <code class="language-plaintext highlighter-rouge">pad()</code> and <code class="language-plaintext highlighter-rouge">format_matrix()</code> from previous solution.</p>

<p>Each of the four requirements gets a new test, and if the matrix fails that test, it returns <code class="language-plaintext highlighter-rouge">0</code> for failure. At the end of the function, it returns <code class="language-plaintext highlighter-rouge">1</code>.</p>

<p>As usual, I use functions from <a href="https://metacpan.org/pod/List::Util">List::Util</a>. <code class="language-plaintext highlighter-rouge">max</code> for <code class="language-plaintext highlighter-rouge">pad</code>, of course, but also <code class="language-plaintext highlighter-rouge">first</code>. I use it here to get the first index of a row that matches the requrement, being the value equalling <code class="language-plaintext highlighter-rouge">1</code>, with <code class="language-plaintext highlighter-rouge">first { $matrix-&gt;[$i][$_] != 0 } 0 .. -1 + scalar @row</code>. I use a lot of the functional tools, like <code class="language-plaintext highlighter-rouge">scalar</code> and <code class="language-plaintext highlighter-rouge">grep</code> and <code class="language-plaintext highlighter-rouge">map</code>, but not exclusively.</p>

<ol>
  <li>Pull each row, removing all zeroes. If there’s any values left, the first has to be a zero, which is a fail.</li>
  <li>If a row only has zeroes, every row below it has to have zeros, so look forward into each row for rows without zeros. If the row, once the zeros are filtered out, has any values, that’s a fail.</li>
  <li>Compare each row with the row before it, finding the index for the leading 1. If the current row’s leading one’s index is greater or equal to the previous row’s leading one’s index, that’s a fail.</li>
  <li>This test is columnar. For each column, find if there’s a <code class="language-plaintext highlighter-rouge">1</code>, then determine if it’s a leading <code class="language-plaintext highlighter-rouge">1</code> by looking for non-zero values in the row it’s in. if it is, set the current position into the column array for zero, check for non-zero characters, and fail if there are.</li>
</ol>

<h4 id="show-me-the-code-1">Show Me The Code!</h4>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env perl</span>

<span class="k">use</span> <span class="nv">strict</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">warnings</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">experimental</span> <span class="sx">qw{ say postderef signatures state }</span><span class="p">;</span>

<span class="k">use</span> <span class="nn">List::</span><span class="nv">Util</span> <span class="sx">qw{ first max }</span><span class="p">;</span>

<span class="k">my</span> <span class="nv">@examples</span> <span class="o">=</span> <span class="p">(</span>

    <span class="p">[</span> <span class="p">[</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span> <span class="p">],</span> <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span> <span class="p">],</span> <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span> <span class="p">]</span> <span class="p">],</span>
    <span class="p">[</span>
        <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span> <span class="p">],</span>
        <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>  <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span> <span class="p">],</span>
        <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>  <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span> <span class="p">],</span>
        <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>  <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span> <span class="p">]</span>
    <span class="p">],</span>
    <span class="p">[</span> <span class="p">[</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">4</span> <span class="p">],</span> <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">7</span> <span class="p">],</span> <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span> <span class="p">]</span> <span class="p">],</span>
    <span class="p">[</span>
        <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span> <span class="p">],</span>
        <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>  <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span> <span class="p">],</span>
        <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>  <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span> <span class="p">],</span>
        <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>  <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span> <span class="p">]</span>
    <span class="p">],</span>
    <span class="p">[</span> <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span> <span class="p">],</span> <span class="p">[</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span> <span class="p">],</span> <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span> <span class="p">]</span> <span class="p">],</span>
    <span class="p">[</span> <span class="p">[</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span> <span class="p">],</span> <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">7</span> <span class="p">],</span> <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span> <span class="p">]</span> <span class="p">]</span>
<span class="p">);</span>

<span class="k">for</span> <span class="k">my</span> <span class="nv">$example</span> <span class="p">(</span><span class="nv">@examples</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">my</span> <span class="nv">$output</span> <span class="o">=</span> <span class="nv">reduced_row_eschelon</span><span class="p">(</span><span class="nv">$example</span><span class="p">);</span>
    <span class="k">my</span> <span class="nv">$input</span>  <span class="o">=</span> <span class="nv">format_matrix</span><span class="p">(</span><span class="nv">$example</span><span class="p">);</span>
    <span class="nv">state</span> <span class="nv">$i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="nv">$i</span><span class="o">++</span><span class="p">;</span>

    <span class="nv">say</span> <span class="o">&lt;&lt;~</span><span class="p">"</span><span class="s2">END</span><span class="p">";</span>
    <span class="nv">Example</span> <span class="nv">$i</span>
        <span class="nv">Input:</span>  <span class="o">\</span><span class="nv">$M</span> <span class="o">=</span> <span class="nv">$input</span>
        <span class="nv">Output:</span> <span class="nv">$output</span>
    <span class="k">END</span>
<span class="p">}</span>

<span class="k">sub </span><span class="nf">reduced_row_eschelon</span> <span class="p">($matrix) {</span>
    <span class="k">my</span> <span class="nv">@is_nonzero_row</span><span class="p">;</span>
    <span class="k">for</span> <span class="k">my</span> <span class="nv">$i</span> <span class="p">(</span> <span class="mi">0</span> <span class="o">..</span> <span class="o">-</span><span class="mi">1</span> <span class="o">+</span> <span class="nb">scalar</span> <span class="nv">$matrix</span><span class="o">-&gt;</span><span class="err">@</span><span class="o">*</span> <span class="p">)</span> <span class="p">{</span>
        <span class="k">my</span> <span class="nv">@row</span> <span class="o">=</span> <span class="nv">$matrix</span><span class="o">-&gt;</span><span class="p">[</span><span class="nv">$i</span><span class="p">]</span><span class="o">-&gt;</span><span class="nv">@*</span><span class="p">;</span>

        <span class="c1"># 1. If a row does not consist entirely of zeros, then the first</span>
        <span class="c1">#    nonzero number in the row is a 1. We call this the leading 1.</span>
        <span class="k">my</span> <span class="nv">@t1</span> <span class="o">=</span> <span class="nb">grep</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">}</span> <span class="nv">@row</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span> <span class="nb">scalar</span> <span class="nv">@t1</span> <span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="mi">0</span> <span class="k">unless</span> <span class="nv">$t1</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="c1"># 2. If there are any rows that consist entirely of zeros, then</span>
        <span class="c1">#    they are grouped together at the bottom of the matrix.</span>
        <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="nb">scalar</span> <span class="nv">@t1</span> <span class="p">)</span> <span class="p">{</span>
            <span class="k">for</span> <span class="k">my</span> <span class="nv">$j</span> <span class="p">(</span> <span class="nv">$i</span> <span class="o">..</span> <span class="o">-</span><span class="mi">1</span> <span class="o">+</span> <span class="nb">scalar</span> <span class="nv">$matrix</span><span class="o">-&gt;</span><span class="err">@</span><span class="o">*</span> <span class="p">)</span> <span class="p">{</span>
                <span class="k">my</span> <span class="nv">$count</span> <span class="o">=</span> <span class="nb">scalar</span> <span class="nb">grep</span> <span class="p">{</span> <span class="vg">$_</span> <span class="ow">ne</span> <span class="mi">0</span> <span class="p">}</span> <span class="nv">$matrix</span><span class="o">-&gt;</span><span class="p">[</span><span class="nv">$j</span><span class="p">]</span><span class="o">-&gt;</span><span class="nv">@*</span><span class="p">;</span>
                <span class="k">return</span> <span class="mi">0</span> <span class="k">if</span> <span class="nv">$count</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="c1"># 3. In any two successive rows that do not consist entirely of zeros,</span>
        <span class="c1">#    the leading 1 in the lower row occurs farther to the right than</span>
        <span class="c1">#    the leading 1 in the higher row.</span>
        <span class="nv">$is_nonzero_row</span><span class="p">[</span><span class="nv">$i</span><span class="p">]</span> <span class="o">=</span> <span class="nb">scalar</span> <span class="nv">@t1</span> <span class="p">?</span> <span class="mi">1</span> <span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span> <span class="nv">$i</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="nv">$is_nonzero_row</span><span class="p">[</span><span class="nv">$i</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="nv">$is_nonzero_row</span><span class="p">[</span> <span class="nv">$i</span> <span class="o">-</span> <span class="mi">1</span> <span class="p">]</span> <span class="p">)</span> <span class="p">{</span>
            <span class="k">my</span> <span class="nv">$curr</span> <span class="o">=</span>
                <span class="nv">first</span> <span class="p">{</span> <span class="nv">$matrix</span><span class="o">-&gt;</span><span class="p">[</span><span class="nv">$i</span><span class="p">][</span><span class="vg">$_</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">}</span> <span class="mi">0</span> <span class="o">..</span> <span class="o">-</span><span class="mi">1</span> <span class="o">+</span> <span class="nb">scalar</span> <span class="nv">@row</span><span class="p">;</span>
            <span class="k">my</span> <span class="nv">$prev</span> <span class="o">=</span>
                <span class="nv">first</span> <span class="p">{</span> <span class="nv">$matrix</span><span class="o">-&gt;</span><span class="p">[</span> <span class="nv">$i</span> <span class="o">-</span> <span class="mi">1</span> <span class="p">][</span><span class="vg">$_</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">}</span> <span class="mi">0</span> <span class="o">..</span> <span class="o">-</span><span class="mi">1</span> <span class="o">+</span> <span class="nb">scalar</span> <span class="nv">@row</span><span class="p">;</span>
            <span class="k">return</span> <span class="mi">0</span> <span class="k">unless</span> <span class="nv">$curr</span> <span class="o">&gt;</span> <span class="nv">$prev</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1"># 4. Each column that contains a leading 1 has zeros everywhere else</span>
    <span class="c1">#    in that column.</span>
    <span class="k">for</span> <span class="k">my</span> <span class="nv">$i</span> <span class="p">(</span> <span class="mi">0</span> <span class="o">..</span> <span class="o">-</span><span class="mi">1</span> <span class="o">+</span> <span class="nb">scalar</span> <span class="nv">$matrix</span><span class="o">-&gt;</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">-&gt;</span><span class="err">@</span><span class="o">*</span> <span class="p">)</span> <span class="p">{</span>

        <span class="c1"># 1.    get the column</span>
        <span class="k">my</span> <span class="nv">@col</span> <span class="o">=</span> <span class="nb">map</span> <span class="p">{</span> <span class="nv">$matrix</span><span class="o">-&gt;</span><span class="p">[</span><span class="vg">$_</span><span class="p">][</span><span class="nv">$i</span><span class="p">]</span> <span class="p">}</span> <span class="mi">0</span> <span class="o">..</span> <span class="o">-</span><span class="mi">1</span> <span class="o">+</span> <span class="nb">scalar</span> <span class="nv">$matrix</span><span class="o">-&gt;</span><span class="nv">@*</span><span class="p">;</span>

        <span class="c1"># 2.    find the 1, determine if it's a leading 1 by checking that row</span>
        <span class="k">if</span> <span class="p">(</span> <span class="nb">grep</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">==</span> <span class="mi">1</span> <span class="p">}</span> <span class="nv">@col</span> <span class="p">)</span> <span class="p">{</span>

            <span class="c1"># for each 1</span>
            <span class="k">my</span> <span class="nv">@ones</span> <span class="o">=</span> <span class="nb">grep</span> <span class="p">{</span> <span class="mi">1</span> <span class="o">==</span> <span class="nv">$col</span><span class="p">[</span><span class="vg">$_</span><span class="p">]</span> <span class="p">}</span> <span class="mi">0</span> <span class="o">..</span> <span class="o">-</span><span class="mi">1</span> <span class="o">+</span> <span class="nb">scalar</span> <span class="nv">@col</span><span class="p">;</span>
            <span class="k">for</span> <span class="k">my</span> <span class="nv">$j</span> <span class="p">(</span><span class="nv">@ones</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">my</span> <span class="nv">@row</span>     <span class="o">=</span> <span class="nv">$matrix</span><span class="o">-&gt;</span><span class="p">[</span><span class="nv">$j</span><span class="p">]</span><span class="o">-&gt;</span><span class="nv">@*</span><span class="p">;</span>
                <span class="k">my</span> <span class="nv">@sub</span>     <span class="o">=</span> <span class="nv">@row</span><span class="p">[</span> <span class="mi">0</span> <span class="o">..</span> <span class="nv">$i</span> <span class="o">-</span> <span class="mi">1</span> <span class="p">];</span>
                <span class="k">my</span> <span class="nv">$leading</span> <span class="o">=</span> <span class="p">(</span> <span class="mi">0</span> <span class="o">==</span> <span class="nb">grep</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">}</span> <span class="nv">@sub</span> <span class="p">)</span> <span class="p">?</span> <span class="mi">1</span> <span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="nv">$leading</span><span class="p">)</span> <span class="p">{</span>
                    <span class="nv">$col</span><span class="p">[</span><span class="nv">$j</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                    <span class="k">my</span> <span class="nv">$zero_count</span> <span class="o">=</span> <span class="nb">scalar</span> <span class="nb">grep</span> <span class="p">{</span> <span class="vg">$_</span> <span class="ow">ne</span> <span class="mi">0</span> <span class="p">}</span> <span class="nv">@col</span><span class="p">;</span>
                    <span class="k">return</span> <span class="mi">0</span> <span class="k">if</span> <span class="nv">$zero_count</span><span class="p">;</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1"># say format_matrix($matrix);</span>
    <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">sub </span><span class="nf">format_matrix</span> <span class="p">($matrix) {</span>
    <span class="k">my</span> <span class="nv">$maxlen</span> <span class="o">=</span> <span class="nv">max</span> <span class="nb">map</span> <span class="p">{</span> <span class="nb">length</span> <span class="vg">$_</span> <span class="p">}</span> <span class="nb">map</span> <span class="p">{</span> <span class="vg">$_</span><span class="o">-&gt;</span><span class="err">@</span><span class="o">*</span> <span class="p">}</span> <span class="nv">$matrix</span><span class="o">-&gt;</span><span class="nv">@*</span><span class="p">;</span>
    <span class="k">my</span> <span class="nv">$output</span> <span class="o">=</span> <span class="nb">join</span> <span class="p">"</span><span class="se">\n</span><span class="s2">                  </span><span class="p">",</span> <span class="p">'</span><span class="s1">[</span><span class="p">',</span> <span class="p">(</span>
        <span class="nb">map</span> <span class="p">{</span> <span class="sx">qq{  [$_],}</span> <span class="p">}</span> <span class="nb">map</span> <span class="p">{</span>
            <span class="nb">join</span> <span class="p">'</span><span class="s1">,</span><span class="p">',</span>
                <span class="nb">map</span> <span class="p">{</span> <span class="nv">pad</span><span class="p">(</span> <span class="vg">$_</span><span class="p">,</span> <span class="mi">1</span> <span class="o">+</span> <span class="nv">$maxlen</span> <span class="p">)</span> <span class="p">}</span>
                <span class="vg">$_</span><span class="o">-&gt;</span><span class="err">@</span><span class="o">*</span>
        <span class="p">}</span> <span class="nb">map</span> <span class="p">{</span> <span class="nv">$matrix</span><span class="o">-&gt;</span><span class="p">[</span><span class="vg">$_</span><span class="p">]</span> <span class="p">}</span> <span class="mi">0</span> <span class="o">..</span> <span class="o">-</span><span class="mi">1</span> <span class="o">+</span> <span class="nb">scalar</span> <span class="nv">$matrix</span><span class="o">-&gt;</span><span class="err">@</span><span class="o">*</span>
        <span class="p">),</span>
        <span class="p">'</span><span class="s1">]</span><span class="p">';</span>
    <span class="k">return</span> <span class="nv">$output</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">sub </span><span class="nf">pad</span> <span class="p">( $str, $len = 4 ) {</span> <span class="k">return</span> <span class="nb">sprintf</span> <span class="p">"</span><span class="s2">%</span><span class="si">${len}</span><span class="s2">s</span><span class="p">",</span> <span class="nv">$str</span><span class="p">;</span> <span class="p">}</span>
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ./ch-2.pl
Example 1
    Input:  $M = [
                    [ 1, 1, 0],
                    [ 0, 1, 0],
                    [ 0, 0, 0],
                  ]
    Output: 0

Example 2
    Input:  $M = [
                    [  0,  1, -2,  0,  1],
                    [  0,  0,  0,  1,  3],
                    [  0,  0,  0,  0,  0],
                    [  0,  0,  0,  0,  0],
                  ]
    Output: 1

Example 3
    Input:  $M = [
                    [  1,  0,  0,  4],
                    [  0,  1,  0,  7],
                    [  0,  0,  1, -1],
                  ]
    Output: 1

Example 4
    Input:  $M = [
                    [  0,  1, -2,  0,  1],
                    [  0,  0,  0,  0,  0],
                    [  0,  0,  0,  1,  3],
                    [  0,  0,  0,  0,  0],
                  ]
    Output: 0

Example 5
    Input:  $M = [
                    [ 0, 1, 0],
                    [ 1, 0, 0],
                    [ 0, 0, 0],
                  ]
    Output: 0

Example 6
    Input:  $M = [
                    [  4,  0,  0,  0],
                    [  0,  1,  0,  7],
                    [  0,  0,  1, -1],
                  ]
    Output: 0
</code></pre></div></div>

<h4 id="if-you-have-any-questions-or-comments-i-would-be-glad-to-hear-it-ask-me-on-mastodon-or-make-an-issue-on-my-blog-repo">If you have any questions or comments, I would be glad to hear it. Ask me on <a href="https://mastodon.xyz/@jacobydave">Mastodon</a> or <a href="https://github.com/jacoby/jacoby.github.io">make an issue on my blog repo.</a></h4>]]></content><author><name>Dave Jacoby</name></author><summary type="html"><![CDATA[Welcome to Weekly Challenge #257! [257(https://en.wikipedia.org/wiki/257(number))] is a _prime number, of the form 22n+1. It is also an irregular prime and a Jacobsthal-Lucas number.]]></summary></entry><entry><title type="html">A Perfect Square Perfectly Squared: Weekly Challenge #256</title><link href="https://jacoby.github.io//2024/02/12/a-perfect-square-perfectly-squared-weekly-challenge-256.html" rel="alternate" type="text/html" title="A Perfect Square Perfectly Squared: Weekly Challenge #256" /><published>2024-02-12T21:28:10+00:00</published><updated>2024-02-12T21:28:10+00:00</updated><id>https://jacoby.github.io//2024/02/12/a-perfect-square-perfectly-squared-weekly-challenge-256</id><content type="html" xml:base="https://jacoby.github.io//2024/02/12/a-perfect-square-perfectly-squared-weekly-challenge-256.html"><![CDATA[<p>Welcome to <strong><a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-256/">Weekly Challenge #256!</a></strong> <strong>256</strong> is a <a href="https://en.wikipedia.org/wiki/Square_number">perfect square</a>, being <strong>16<sup>2</sup></strong>. Of course, <strong>4<sup>2</sup> = 16</strong>, and also <strong>2<sup>2</sup> = 4</strong>, so 256 is a perfect square of a perfect square of a perfect square.</p>

<p><strong>256</strong> is also <a href="https://en.wikipedia.org/wiki/Area_codes_256_and_938">the area code of Huntsville, Alabama</a>, a fact that must amuse some rocket scientists.</p>

<h3 id="task-1-maximum-pairs">Task 1: Maximum Pairs</h3>

<blockquote>
  <p>Submitted by: Mohammad Sajid Anwar
You are given an array of distinct words, @words.</p>

  <p>Write a script to find the maximum pairs in the given array. The words $words[i] and $words[j] can be a pair one is reverse of the other.</p>
</blockquote>

<h4 id="lets-talk-about-it">Let’s Talk About It</h4>

<p>So, we’re given an array of words. In the example cases, they’re all two-letter words. A <em>pair</em> is when two words, when sorted, are the same. <code class="language-plaintext highlighter-rouge">pw</code> and <code class="language-plaintext highlighter-rouge">wp</code> would be a pair, because they’re both <code class="language-plaintext highlighter-rouge">wp</code>.</p>

<p>I use <code class="language-plaintext highlighter-rouge">map</code> in a void context again, instead of a <code class="language-plaintext highlighter-rouge">for</code> loop, splitting and sorting and joining each word, then use <code class="language-plaintext highlighter-rouge">map { $hash{$_}++}</code> to count all the individual munged words.</p>

<p>So, we have a pair when <code class="language-plaintext highlighter-rouge">$hash{$munge} &gt; 1</code>, so I <code class="language-plaintext highlighter-rouge">grep</code> for that, and use <code class="language-plaintext highlighter-rouge">scalar</code> to get the count of what passes.</p>

<h4 id="show-me-the-code">Show Me The Code!</h4>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env perl</span>

<span class="k">use</span> <span class="nv">strict</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">warnings</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">experimental</span> <span class="sx">qw{ say postderef signatures state }</span><span class="p">;</span>

<span class="k">my</span> <span class="nv">@examples</span> <span class="o">=</span> <span class="p">(</span>

    <span class="p">[</span> <span class="p">"</span><span class="s2">ab</span><span class="p">",</span> <span class="p">"</span><span class="s2">de</span><span class="p">",</span> <span class="p">"</span><span class="s2">ed</span><span class="p">",</span> <span class="p">"</span><span class="s2">bc</span><span class="p">"</span> <span class="p">],</span>
    <span class="p">[</span> <span class="p">"</span><span class="s2">aa</span><span class="p">",</span> <span class="p">"</span><span class="s2">ba</span><span class="p">",</span> <span class="p">"</span><span class="s2">cd</span><span class="p">",</span> <span class="p">"</span><span class="s2">ed</span><span class="p">"</span> <span class="p">],</span>
    <span class="p">[</span> <span class="p">"</span><span class="s2">uv</span><span class="p">",</span> <span class="p">"</span><span class="s2">qp</span><span class="p">",</span> <span class="p">"</span><span class="s2">st</span><span class="p">",</span> <span class="p">"</span><span class="s2">vu</span><span class="p">",</span> <span class="p">"</span><span class="s2">mn</span><span class="p">",</span> <span class="p">"</span><span class="s2">pq</span><span class="p">"</span> <span class="p">],</span>
<span class="p">);</span>

<span class="k">for</span> <span class="k">my</span> <span class="nv">$example</span> <span class="p">(</span><span class="nv">@examples</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">my</span> <span class="nv">$input</span>  <span class="o">=</span> <span class="nb">join</span> <span class="p">'</span><span class="s1">, </span><span class="p">',</span> <span class="nb">map</span> <span class="p">{</span> <span class="sx">qq {"$_"} </span><span class="p">}</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="nv">@*</span><span class="p">;</span>
    <span class="k">my</span> <span class="nv">$output</span> <span class="o">=</span> <span class="nv">maximum_pairs</span><span class="p">(</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="err">@</span><span class="o">*</span> <span class="p">);</span>

    <span class="nv">say</span> <span class="o">&lt;&lt;~</span><span class="p">"</span><span class="s2">END</span><span class="p">";</span>
    <span class="nv">Input:</span>  <span class="o">\</span><span class="nv">@words</span> <span class="o">=</span> <span class="p">(</span><span class="nv">$input</span><span class="p">)</span>
    <span class="nv">Output:</span> <span class="nv">$output</span>
    <span class="k">END</span>
<span class="p">}</span>

<span class="k">sub </span><span class="nf">maximum_pairs</span> <span class="p">(@input) {</span>
    <span class="k">my</span> <span class="nv">%hash</span><span class="p">;</span>
    <span class="nb">map</span> <span class="p">{</span>
        <span class="k">my</span> <span class="nv">$munge</span> <span class="o">=</span> <span class="nb">join</span> <span class="p">'',</span> <span class="nb">sort</span> <span class="nb">split</span> <span class="sr">//</span><span class="p">,</span> <span class="vg">$_</span><span class="p">;</span>
        <span class="nv">$hash</span><span class="p">{</span><span class="nv">$munge</span><span class="p">}</span><span class="o">++</span>
    <span class="p">}</span> <span class="nv">@input</span><span class="p">;</span>
    <span class="k">return</span> <span class="nb">scalar</span> <span class="nb">grep</span> <span class="p">{</span> <span class="vg">$_</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="p">}</span> <span class="nb">values</span> <span class="nv">%hash</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ./ch-1.pl
Input:  @words = ("ab", "de", "ed", "bc")
Output: 1

Input:  @words = ("aa", "ba", "cd", "ed")
Output: 0

Input:  @words = ("uv", "qp", "st", "vu", "mn", "pq")
Output: 2
</code></pre></div></div>

<h3 id="task-2-merge-strings">Task 2: Merge Strings</h3>

<blockquote>
  <p>Submitted by: Mohammad Sajid Anwar
You are given two strings, $str1 and $str2.</p>

  <p>Write a script to merge the given strings by adding in alternative order starting with the first string. If a string is longer than the other then append the remaining at the end.</p>
</blockquote>

<h4 id="lets-talk-about-it-1">Let’s Talk About It</h4>

<p>Normally, I would want to <code class="language-plaintext highlighter-rouge">split</code> both into arrays, then <code class="language-plaintext highlighter-rouge">push</code> the output into an array, one character at a time. I decided to do this with strings instead.</p>

<p>While there’s both <code class="language-plaintext highlighter-rouge">$string</code> and <code class="language-plaintext highlighter-rouge">$string2</code>, I use <code class="language-plaintext highlighter-rouge">substr</code> to add the first characters to the output, then remove both first characters. I do this by using <code class="language-plaintext highlighter-rouge">substr</code> as both an <a href="https://perldoc.perl.org/perlglossary#lvalue">lvalue</a>, capable of being written to, and an <a href="https://perldoc.perl.org/perlglossary#rvalue">rvalue</a>, capable of being read from. That’s so very useful.</p>

<p>Once one string or the other is empty, whe stop the <code class="language-plaintext highlighter-rouge">while</code> loop and join the remaining string to the output. Thing is, if either <code class="language-plaintext highlighter-rouge">$string1</code> or <code class="language-plaintext highlighter-rouge">$string2</code> is empty, <code class="language-plaintext highlighter-rouge">$output . $string1 . $string2</code> is equivalent to <code class="language-plaintext highlighter-rouge">$output . $string2 . $string1</code>, so returning the concatenated string finishes the job with no array-related functions like <code class="language-plaintext highlighter-rouge">join</code>.</p>

<h4 id="show-me-the-code-1">Show Me The Code!</h4>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env perl</span>

<span class="k">use</span> <span class="nv">strict</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">warnings</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">experimental</span> <span class="sx">qw{ say postderef signatures state }</span><span class="p">;</span>

<span class="k">my</span> <span class="nv">@examples</span> <span class="o">=</span> <span class="p">(</span>

    <span class="p">[</span> <span class="p">"</span><span class="s2">abcd</span><span class="p">",</span>   <span class="p">"</span><span class="s2">1234</span><span class="p">"</span> <span class="p">],</span>
    <span class="p">[</span> <span class="p">"</span><span class="s2">abc</span><span class="p">",</span>    <span class="p">"</span><span class="s2">12345</span><span class="p">"</span> <span class="p">],</span>
    <span class="p">[</span> <span class="p">"</span><span class="s2">abcde</span><span class="p">",</span>  <span class="p">"</span><span class="s2">123</span><span class="p">"</span> <span class="p">],</span>
<span class="p">);</span>

<span class="k">for</span> <span class="k">my</span> <span class="nv">$example</span> <span class="p">(</span><span class="nv">@examples</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">my</span> <span class="nv">$output</span> <span class="o">=</span> <span class="nv">merge_strings</span><span class="p">(</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="err">@</span><span class="o">*</span> <span class="p">);</span>
    <span class="k">my</span> <span class="nv">$p</span>      <span class="o">=</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
    <span class="k">my</span> <span class="nv">$w</span>      <span class="o">=</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="nv">say</span> <span class="o">&lt;&lt;~</span><span class="p">"</span><span class="s2">END</span><span class="p">";</span>
    <span class="nv">Input:</span>  <span class="o">\</span><span class="nv">$str1</span> <span class="o">=</span> <span class="p">"</span><span class="si">$p</span><span class="p">",</span> <span class="o">\</span><span class="nv">$str2</span> <span class="o">=</span> <span class="p">"</span><span class="si">$w</span><span class="p">"</span>
    <span class="nv">Output:</span> <span class="p">"</span><span class="si">$output</span><span class="p">"</span>
    <span class="k">END</span>
<span class="p">}</span>

<span class="k">sub </span><span class="nf">merge_strings</span> <span class="p">( $str1, $str2 ) {</span>
    <span class="k">my</span> <span class="nv">$output</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span> <span class="nb">length</span> <span class="nv">$str1</span> <span class="o">&amp;&amp;</span> <span class="nb">length</span> <span class="nv">$str2</span> <span class="p">)</span> <span class="p">{</span>
        <span class="nv">$output</span> <span class="o">.=</span> <span class="nb">substr</span><span class="p">(</span> <span class="nv">$str1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span> <span class="p">)</span> <span class="o">.</span>  <span class="nb">substr</span><span class="p">(</span> <span class="nv">$str2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span> <span class="p">);</span>
        <span class="nb">substr</span><span class="p">(</span> <span class="nv">$str1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span> <span class="p">)</span> <span class="o">=</span> <span class="p">'';</span>
        <span class="nb">substr</span><span class="p">(</span> <span class="nv">$str2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span> <span class="p">)</span> <span class="o">=</span> <span class="p">'';</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nv">$output</span> <span class="o">.</span> <span class="nv">$str1</span> <span class="o">.</span> <span class="nv">$str2</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ./ch-2.pl
Input:  $str1 = "abcd", $str2 = "1234"
Output: "a1b2c3d4"

Input:  $str1 = "abc", $str2 = "12345"
Output: "a1b2c345"

Input:  $str1 = "abcde", $str2 = "123"
Output: "a1b2c3de"

</code></pre></div></div>

<h4 id="if-you-have-any-questions-or-comments-i-would-be-glad-to-hear-it-ask-me-on-mastodon-or-make-an-issue-on-my-blog-repo">If you have any questions or comments, I would be glad to hear it. Ask me on <a href="https://mastodon.xyz/@jacobydave">Mastodon</a> or <a href="https://github.com/jacoby/jacoby.github.io">make an issue on my blog repo.</a></h4>]]></content><author><name>Dave Jacoby</name></author><summary type="html"><![CDATA[Welcome to Weekly Challenge #256! 256 is a perfect square, being 162. Of course, 42 = 16, and also 22 = 4, so 256 is a perfect square of a perfect square of a perfect square.]]></summary></entry><entry><title type="html">Preel Weeakly: Weekly Challenge #255</title><link href="https://jacoby.github.io//2024/02/05/preel-weeakly-weekly-challenge-255.html" rel="alternate" type="text/html" title="Preel Weeakly: Weekly Challenge #255" /><published>2024-02-05T18:34:27+00:00</published><updated>2024-02-05T18:34:27+00:00</updated><id>https://jacoby.github.io//2024/02/05/preel-weeakly-weekly-challenge-255</id><content type="html" xml:base="https://jacoby.github.io//2024/02/05/preel-weeakly-weekly-challenge-255.html"><![CDATA[<p>Welcome to <strong><a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-255/">Weekly Challenge #255!</a></strong>, <strong>255</strong> is the product of <strong>3, 5 and 17</strong>. It also equals <strong>2<sup>8</sup> - 1</strong>, which makes it a <strong><a href="https://en.wikipedia.org/wiki/Mersenne_prime">Mersenne number</a></strong> but not a <strong>Mersenne Prime</strong>. And, of course, it is <strong>11111111</strong> in binary, which is the largest integer which can be represented by one byte.</p>

<h3 id="task-1-odd-character">Task 1: Odd Character</h3>

<blockquote>
  <p>Submitted by: Mohammad Sajid Anwar</p>

  <p>You are given two strings, <code class="language-plaintext highlighter-rouge">$s</code> and <code class="language-plaintext highlighter-rouge">$t</code>. The string <code class="language-plaintext highlighter-rouge">$t</code> is generated using the shuffled characters of the string <code class="language-plaintext highlighter-rouge">$s</code> with an additional character.</p>

  <p>Write a script to find the additional character in the string <code class="language-plaintext highlighter-rouge">$t</code>..</p>
</blockquote>

<h4 id="lets-talk-about-it">Let’s Talk About It</h4>

<p>I wanted to use <a href="https://metacpan.org/pod/List::Compare">List::Compare</a>. It’s a good module and is worth pushing, but…</p>

<p>OK, there <em>could</em> be a way to use List::Compare to do this, but I don’t know it off the top of my head. The problem is with <code class="language-plaintext highlighter-rouge">Perl</code> and <code class="language-plaintext highlighter-rouge">Preel</code>, and the <code class="language-plaintext highlighter-rouge">e</code>. List::Compare saw that both sides being compared had an <code class="language-plaintext highlighter-rouge">e</code> and that was good enough.</p>

<p>But that’s OK, because it gave me a license to hack. Both strings were split into arrays and sorted, so that the equivalent letters come out. <code class="language-plaintext highlighter-rouge">"Perl"</code> becomes <code class="language-plaintext highlighter-rouge">["P", "e", "l", "r"]</code> and <code class="language-plaintext highlighter-rouge">"Preel"</code> becomes <code class="language-plaintext highlighter-rouge">["P", "e", "e", "l", "r"]</code>.</p>

<p>We then compare the arrays, one element at a time. I do it destructively, <code class="language-plaintext highlighter-rouge">pop</code>ing the elements, rather than keeping indexes, but that would work too. If the characters are the same, pop both. Else, if one array is longer than the other, pop that and put it in the output. By the rules and examples, the second word should be longer, but this code handles both cases.</p>

<p>(Remember the <em>X-Files</em> movie? Early in it, after the inciting incident happens and the conspiracy people show up, one character, Bronschweig, says this line: <strong>“Sir, the impossible scenario we never planned for? Well, we better come up with a plan.”</strong> There are cases in if statements that should not happen, like a case where the arrays don’t start with the same character but neither is longer than the other. I always try to reference that line when writing an “impossible” case.)</p>

<h4 id="show-me-the-code">Show Me The Code!</h4>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env perl</span>

<span class="k">use</span> <span class="nv">strict</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">warnings</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">experimental</span> <span class="sx">qw{ say postderef signatures state }</span><span class="p">;</span>

<span class="k">use</span> <span class="nv">Carp</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">List::</span><span class="nv">Compare</span><span class="p">;</span>

<span class="k">my</span> <span class="nv">@examples</span> <span class="o">=</span> <span class="p">(</span>

    <span class="p">{</span> <span class="sr">s =&gt; "Perl",   t =&gt; "Preel" },
    { s =</span><span class="o">&gt;</span> <span class="p">"</span><span class="s2">Weekly</span><span class="p">",</span> <span class="s">t</span> <span class="o">=&gt;</span> <span class="p">"</span><span class="s2">Weeakly</span><span class="p">"</span> <span class="p">},</span>
    <span class="p">{</span> <span class="sr">s =&gt; "Box",    t =&gt; "Boxy" },
);

for my $example (@examples) {
    my $output =</span> <span class="nv">odd_character</span><span class="p">(</span><span class="nv">$example</span><span class="p">);</span>
    <span class="k">my</span> <span class="nv">$s</span>      <span class="o">=</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="p">{</span><span class="sr">s};
    my $t      = $example-&gt;{t};

    say &lt;&lt;~"END";
    Input:  \$s = "$s" \$t = "$t"
    Output: $output
    END
}</span>

<span class="k">sub </span><span class="nf">odd_character</span> <span class="p">($input) {</span>
    <span class="k">my</span> <span class="nv">@s</span> <span class="o">=</span> <span class="nb">sort</span> <span class="nb">split</span> <span class="sr">//</span><span class="p">,</span> <span class="nv">$input</span><span class="o">-&gt;</span><span class="p">{</span><span class="sr">s};
    my @t = sort split //, $input-&gt;{t};
    my @output;
    while ( @s &amp;&amp; @t ) {
        if ( $s[0] eq $t[0] ) {
            shift @s;
            shift @t;
        }</span>
        <span class="k">else</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span> <span class="nb">scalar</span> <span class="nv">@s</span> <span class="o">&gt;</span> <span class="nb">scalar</span> <span class="nv">@t</span> <span class="p">)</span> <span class="p">{</span>
                <span class="nb">push</span> <span class="nv">@output</span><span class="p">,</span> <span class="nb">shift</span> <span class="nv">@s</span><span class="p">;</span>
            <span class="p">}</span>
            <span class="k">elsif</span> <span class="p">(</span> <span class="nb">scalar</span> <span class="nv">@s</span> <span class="o">&lt;</span> <span class="nb">scalar</span> <span class="nv">@t</span> <span class="p">)</span> <span class="p">{</span>
                <span class="nb">push</span> <span class="nv">@output</span><span class="p">,</span> <span class="nb">shift</span> <span class="nv">@t</span><span class="p">;</span>
            <span class="p">}</span>
            <span class="k">else</span> <span class="p">{</span> <span class="nv">croak</span> <span class="p">'</span><span class="s1">Impossible Scenario</span><span class="p">'</span> <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="nb">push</span> <span class="nv">@output</span><span class="p">,</span> <span class="nv">@s</span> <span class="k">if</span> <span class="nv">@s</span><span class="p">;</span>
    <span class="nb">push</span> <span class="nv">@output</span><span class="p">,</span> <span class="nv">@t</span> <span class="k">if</span> <span class="nv">@t</span><span class="p">;</span>
    <span class="k">return</span> <span class="nb">shift</span> <span class="nv">@output</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ./ch-1.pl
Input:  $s = "Perl" $t = "Preel"
Output: e

Input:  $s = "Weekly" $t = "Weeakly"
Output: a

Input:  $s = "Box" $t = "Boxy"
Output: y
</code></pre></div></div>

<h3 id="task-2-most-frequent-word">Task 2: Most Frequent Word</h3>

<blockquote>
  <p>Submitted by: Mohammad Sajid Anwar<br />
You are given a paragraph <code class="language-plaintext highlighter-rouge">$p</code> and a banned word <code class="language-plaintext highlighter-rouge">$w</code>.</p>

  <p>Write a script to return the most frequent word that is not banned.</p>
</blockquote>

<h4 id="lets-talk-about-it-1">Let’s Talk About It</h4>

<p>I have done something and I feel no guilt about it.</p>

<p>I have committed (and now have published) functional code that uses <code class="language-plaintext highlighter-rouge">map</code> but doesn’t fill an array. I have used it as a loop. <code class="language-plaintext highlighter-rouge">map { $hash{$_}++ } 1..10</code> wastes the result, but that would just be ten <code class="language-plaintext highlighter-rouge">1</code>s. I have seen people arguing that it’s bad form, but besides maybe being slower (I could <a href="https://metacpan.org/pod/Benchmark">Benchmark</a> it to know for sure), I don’t see any solid reason why the functional technique is worse than loops.</p>

<p>But anyway, we split on one or more non-word characters <code class="language-plaintext highlighter-rouge">/\W+/</code>, which has the possibility of breaking <code class="language-plaintext highlighter-rouge">"isn't"</code> into <code class="language-plaintext highlighter-rouge">"isn"</code> and <code class="language-plaintext highlighter-rouge">"t"</code>, but the examples contain no contractions.</p>

<p>There’s a thing that’s ambiguous to me. Second example has <code class="language-plaintext highlighter-rouge">the</code> as the blocked word, but it isn’t clear if <code class="language-plaintext highlighter-rouge">The</code> would also be blocked. That the correct output is <code class="language-plaintext highlighter-rouge">Perl</code> and not <code class="language-plaintext highlighter-rouge">perl</code> indicates to me that code folding isn’t part of the solution. But while I’m mentioning that I’m not doing it, I think I should explain. We would previously write <code class="language-plaintext highlighter-rouge">lc $x eq lc $y</code> to compare to strings without bothering with case, but <code class="language-plaintext highlighter-rouge">lc</code> and <code class="language-plaintext highlighter-rouge">uc</code> don’t affect Unicode, which is increasingly common in text. <a href="https://perldoc.perl.org/functions/fc"><code class="language-plaintext highlighter-rouge">fc</code></a> works with Unicode.</p>

<p>Anyway, we use <code class="language-plaintext highlighter-rouge">grep</code> to ensure that the blocked word doesn’t get considered, and then <code class="language-plaintext highlighter-rouge">map { $hash{$_} ++ }</code> as discussed previously, to count each word. Once we’re done, we can use <code class="language-plaintext highlighter-rouge">max</code> from the perrenial favorite, <a href="https://metacpan.org/pod/List::Util">List::Util</a>, on the hash. <code class="language-plaintext highlighter-rouge">keys</code> gives a list of keys to the hash, but <code class="language-plaintext highlighter-rouge">values</code> gives you access to the count, and thus we get the highest count. <code class="language-plaintext highlighter-rouge">grep {$hash{$_} == $max}</code> gives us a list of words that make that high count (presumably a list of one element), and then <code class="language-plaintext highlighter-rouge">return shift @output</code> gives us the first (only) entry and the correct solution.</p>

<p>If abusing functional techniques is wrong, I don’t want to be right.</p>

<h4 id="show-me-the-code-1">Show Me The Code!</h4>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env perl</span>

<span class="k">use</span> <span class="nv">strict</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">warnings</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">experimental</span> <span class="sx">qw{ say postderef signatures state fc }</span><span class="p">;</span>

<span class="k">use</span> <span class="nn">List::</span><span class="nv">Util</span> <span class="sx">qw{ max }</span><span class="p">;</span>

<span class="k">my</span> <span class="nv">@examples</span> <span class="o">=</span> <span class="p">(</span>

    <span class="p">{</span>
        <span class="s">paragraph</span> <span class="o">=&gt;</span>
            <span class="p">"</span><span class="s2">Joe hit a ball, the hit ball flew far after it was hit.</span><span class="p">",</span>
        <span class="s">word</span> <span class="o">=&gt;</span> <span class="p">"</span><span class="s2">hit</span><span class="p">",</span>
    <span class="p">},</span>
    <span class="p">{</span>
        <span class="s">paragraph</span> <span class="o">=&gt;</span>
<span class="p">"</span><span class="s2">Perl and Raku belong to the same family. Perl is the most popular language in the weekly challenge.</span><span class="p">",</span>
        <span class="s">word</span> <span class="o">=&gt;</span> <span class="p">"</span><span class="s2">the</span><span class="p">",</span>
    <span class="p">}</span>
<span class="p">);</span>

<span class="k">for</span> <span class="k">my</span> <span class="nv">$example</span> <span class="p">(</span><span class="nv">@examples</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">my</span> <span class="nv">$output</span> <span class="o">=</span> <span class="nv">most_frequent_word</span><span class="p">(</span><span class="nv">$example</span><span class="p">);</span>
    <span class="k">my</span> <span class="nv">$p</span> <span class="o">=</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="p">{</span><span class="nv">paragraph</span><span class="p">};</span>
    <span class="k">my</span> <span class="nv">$w</span> <span class="o">=</span> <span class="nv">$example</span><span class="o">-&gt;</span><span class="p">{</span><span class="nv">word</span><span class="p">};</span>

    <span class="nv">say</span> <span class="o">&lt;&lt;~</span><span class="p">"</span><span class="s2">END</span><span class="p">";</span>
    <span class="nv">Input:</span>  <span class="o">\</span><span class="nv">$p</span> <span class="o">=</span> <span class="p">"</span><span class="si">$p</span><span class="p">"</span>
            <span class="o">\</span><span class="nv">$w</span> <span class="o">=</span> <span class="p">"</span><span class="si">$w</span><span class="p">"</span>
    <span class="nv">Output:</span> <span class="p">"</span><span class="si">$output</span><span class="p">"</span>
    <span class="k">END</span>
<span class="p">}</span>

<span class="k">sub </span><span class="nf">most_frequent_word</span> <span class="p">($obj) {</span>
    <span class="k">my</span> <span class="nv">$paragraph</span>   <span class="o">=</span> <span class="nv">$obj</span><span class="o">-&gt;</span><span class="p">{</span><span class="nv">paragraph</span><span class="p">};</span>
    <span class="k">my</span> <span class="nv">$banned_word</span> <span class="o">=</span> <span class="nv">$obj</span><span class="o">-&gt;</span><span class="p">{</span><span class="nv">word</span><span class="p">};</span>
    <span class="k">my</span> <span class="nv">%hash</span><span class="p">;</span>

    <span class="c1"># some people REALLY hate map being used in this way, believing</span>
    <span class="c1"># that it should end in (start with) @array = , but clearly,</span>
    <span class="nb">map</span> <span class="p">{</span> <span class="nv">$hash</span><span class="p">{</span><span class="vg">$_</span><span class="p">}</span><span class="o">++</span> <span class="p">}</span>
        <span class="nb">grep</span> <span class="p">{</span> <span class="vg">$_</span> <span class="ow">ne</span> <span class="nv">$banned_word</span> <span class="p">}</span>
        <span class="nb">split</span> <span class="sr">/\W+/</span><span class="p">,</span> <span class="nv">$paragraph</span><span class="p">;</span>
    <span class="k">my</span> <span class="nv">$max</span> <span class="o">=</span> <span class="nv">max</span> <span class="nb">values</span> <span class="nv">%hash</span><span class="p">;</span>
    <span class="k">my</span> <span class="nv">@output</span> <span class="o">=</span>
        <span class="nb">grep</span> <span class="p">{</span> <span class="nv">$hash</span><span class="p">{</span><span class="vg">$_</span><span class="p">}</span> <span class="o">==</span> <span class="nv">$max</span> <span class="p">}</span> <span class="nb">keys</span> <span class="nv">%hash</span><span class="p">;</span>
    <span class="k">return</span> <span class="nb">shift</span> <span class="nv">@output</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ./ch-2.pl
Input:  $p = "Joe hit a ball, the hit ball flew far after it was hit."
        $w = "hit"
Output: "ball"

Input:  $p = "Perl and Raku belong to the same family. Perl is the most popular language in the weekly challenge."
        $w = "the"
Output: "Perl"
</code></pre></div></div>

<h4 id="if-you-have-any-questions-or-comments-i-would-be-glad-to-hear-it-ask-me-on-mastodon-or-make-an-issue-on-my-blog-repo">If you have any questions or comments, I would be glad to hear it. Ask me on <a href="https://mastodon.xyz/@jacobydave">Mastodon</a> or <a href="https://github.com/jacoby/jacoby.github.io">make an issue on my blog repo.</a></h4>]]></content><author><name>Dave Jacoby</name></author><summary type="html"><![CDATA[Welcome to Weekly Challenge #255!, 255 is the product of 3, 5 and 17. It also equals 28 - 1, which makes it a Mersenne number but not a Mersenne Prime. And, of course, it is 11111111 in binary, which is the largest integer which can be represented by one byte.]]></summary></entry><entry><title type="html">reverse_vowels(‘Weekly Challenge’) eq ‘Weekly Challenge’: Weekly Challenge #254</title><link href="https://jacoby.github.io//2024/01/29/reverse_vowelsweekly-challenge-eq-weekly-challenge-weekly-challenge-254.html" rel="alternate" type="text/html" title="reverse_vowels(‘Weekly Challenge’) eq ‘Weekly Challenge’: Weekly Challenge #254" /><published>2024-01-29T20:43:30+00:00</published><updated>2024-01-29T20:43:30+00:00</updated><id>https://jacoby.github.io//2024/01/29/reverse_vowelsweekly-challenge-eq-weekly-challenge-weekly-challenge-254</id><content type="html" xml:base="https://jacoby.github.io//2024/01/29/reverse_vowelsweekly-challenge-eq-weekly-challenge-weekly-challenge-254.html"><![CDATA[<p>Welcome to <strong><a href="">Weekly Challenge #254!</a></strong> <strong>254</strong>, the product of <strong>2 and 127</strong>, is a <em>semiprime</em> number. It is <a href="https://en.wikipedia.org/wiki/Deficient_number">deficient</a>, in that the sum of its divisors is <strong>130</strong>, which is less than itself.</p>

<p><strong>254</strong> is also the area code for <a href="https://www.allareacodes.com/254">Waco, Texas</a>.</p>

<h3 id="task-1-three-power">Task 1: Three Power</h3>

<blockquote>
  <p>Submitted by: Mohammad S Anwar<br />
You are given a positive integer, <code class="language-plaintext highlighter-rouge">$n</code>.</p>

  <p>Write a script to return <strong>true</strong> if the given integer is a power of three otherwise return <strong>false</strong>.</p>
</blockquote>

<h4 id="lets-talk-about-it">Let’s Talk About It</h4>

<p>So, cube roots are easy. <code class="language-plaintext highlighter-rouge">$n ** 3</code> gets you the cube, and <code class="language-plaintext highlighter-rouge">$n ** 1/3</code> gets you the cube root.</p>

<p>But it isn’t that simple, because <em>everything</em> is a power of three if you get beyond whole numbers. And that’s the core of my test. <code class="language-plaintext highlighter-rouge">$n == int $n</code>. If we cast as an integer, wiping away the floating point, are they still equal?</p>

<h4 id="show-me-the-code">Show Me The Code!</h4>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env perl</span>

<span class="k">use</span> <span class="nv">strict</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">warnings</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">experimental</span> <span class="sx">qw{ say postderef signatures state }</span><span class="p">;</span>

<span class="k">my</span> <span class="nv">@examples</span> <span class="o">=</span> <span class="p">(</span> <span class="mi">27</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">6</span> <span class="p">);</span>

<span class="k">for</span> <span class="k">my</span> <span class="nv">$example</span> <span class="p">(</span><span class="nv">@examples</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">my</span> <span class="nv">$output</span>    <span class="o">=</span> <span class="nv">three_power</span><span class="p">(</span><span class="nv">$example</span><span class="p">);</span>
    <span class="nv">say</span> <span class="nv">$output</span><span class="p">;</span>

    <span class="nv">say</span> <span class="o">&lt;&lt;~</span><span class="p">"</span><span class="s2">END</span><span class="p">";</span>
    <span class="nv">Input:</span>  <span class="o">\</span><span class="nv">$n</span> <span class="o">=</span> <span class="nv">$example</span>
    <span class="nv">Output:</span> <span class="nv">$output</span>
    <span class="k">END</span>
<span class="p">}</span>

<span class="k">sub </span><span class="nf">three_power</span> <span class="p">($input) {</span>
    <span class="k">my</span> <span class="nv">$cuberoot</span><span class="o">=</span> <span class="nv">$input</span> <span class="o">**</span> <span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="mi">3</span><span class="p">);</span>
    <span class="k">return</span> <span class="p">(</span> <span class="nv">$cuberoot</span> <span class="o">==</span> <span class="nb">int</span> <span class="nv">$cuberoot</span> <span class="p">)</span> <span class="p">?</span> <span class="p">'</span><span class="s1">true</span><span class="p">'</span> <span class="p">:</span> <span class="p">'</span><span class="s1">false</span><span class="p">';</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ./ch-1.pl 
true
Input:  $n = 27
Output: true

true
Input:  $n = 0
Output: true

false
Input:  $n = 6
Output: false
</code></pre></div></div>

<h3 id="task-2-reverse-vowels">Task 2: Reverse Vowels</h3>

<blockquote>
  <p>Submitted by: Mohammad S Anwar<br />
You are given a string, <code class="language-plaintext highlighter-rouge">$s</code>.</p>

  <p>Write a script to reverse all the vowels (a, e, i, o, u) in the given string.</p>
</blockquote>

<h4 id="lets-talk-about-it-1">Let’s Talk About It</h4>

<p>We’ll want a list of all the vowels in the string, so we’ll break apart the string (<code class="language-plaintext highlighter-rouge">split //, $string</code>), collect the vowels ( <code class="language-plaintext highlighter-rouge">grep {/[aeiou]/mix}</code>), make them all lowercase for convenience (<code class="language-plaintext highlighter-rouge">map {lc}</code>) and <code class="language-plaintext highlighter-rouge">reverse</code> them, so they’re in the right order when we start to replace.</p>

<p>Which we do with <code class="language-plaintext highlighter-rouge">substr</code>, which works as both an <strong>lvalue</strong> (<code class="language-plaintext highlighter-rouge">substr($string,1,1) = $char</code>) and an <strong>rvalue</strong> (<code class="language-plaintext highlighter-rouge">$char = substr($string,1,1)</code>). We loop through an index value for all characters, testing if it’s a vowel (again with <code class="language-plaintext highlighter-rouge">/[aeiou]/mix</code>), converting to the case of the letter it replaces (<code class="language-plaintext highlighter-rouge">$n = uc $n if $c eq uc $c</code>), then replacing (<code class="language-plaintext highlighter-rouge">substr( $string, $i, 1 ) = $n</code>).</p>

<p>I’ll point out that both <code class="language-plaintext highlighter-rouge">Perl</code> from the examples and <code class="language-plaintext highlighter-rouge">weekly challenge</code> come out the same, because their vowels are <em>palindromic:</em> <code class="language-plaintext highlighter-rouge">e</code> and <code class="language-plaintext highlighter-rouge">eeaee</code> and the case may be, so <code class="language-plaintext highlighter-rouge">e</code> replaced <code class="language-plaintext highlighter-rouge">e</code>. They’re <em>totally</em> different <code class="language-plaintext highlighter-rouge">e</code>s, I swear.</p>

<h4 id="show-me-the-code-1">Show Me The Code!</h4>

<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env perl</span>

<span class="k">use</span> <span class="nv">strict</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">warnings</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">experimental</span> <span class="sx">qw{ say postderef signatures state }</span><span class="p">;</span>

<span class="k">use</span> <span class="nn">List::</span><span class="nv">Util</span> <span class="sx">qw{ max sum0 }</span><span class="p">;</span>

<span class="k">my</span> <span class="nv">@examples</span> <span class="o">=</span> <span class="p">(</span> <span class="p">"</span><span class="s2">Raku</span><span class="p">",</span> <span class="p">"</span><span class="s2">Perl</span><span class="p">",</span> <span class="p">"</span><span class="s2">Julia</span><span class="p">",</span> <span class="p">"</span><span class="s2">Uiua</span><span class="p">",</span> <span class="p">"</span><span class="s2">Dave</span><span class="p">",</span> <span class="p">'</span><span class="s1">signatures</span><span class="p">',</span> <span class="p">'</span><span class="s1">weekly challenge</span><span class="p">'</span> <span class="p">);</span>

<span class="k">for</span> <span class="k">my</span> <span class="nv">$example</span> <span class="p">(</span><span class="nv">@examples</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">my</span> <span class="nv">$output</span> <span class="o">=</span> <span class="nv">reverse_vowels</span><span class="p">(</span><span class="nv">$example</span><span class="p">);</span>

    <span class="nv">say</span> <span class="o">&lt;&lt;~</span><span class="p">"</span><span class="s2">END</span><span class="p">";</span>
    <span class="nv">Input:</span>  <span class="o">\</span><span class="nv">$s</span> <span class="o">=</span> <span class="p">"</span><span class="si">$example</span><span class="p">"</span>
    <span class="nv">Output:</span> <span class="p">"</span><span class="si">$output</span><span class="p">"</span>
    <span class="k">END</span>
<span class="p">}</span>

<span class="k">sub </span><span class="nf">reverse_vowels</span> <span class="p">($string) {</span>
    <span class="k">my</span> <span class="nv">@vowels</span> <span class="o">=</span>
        <span class="nb">reverse</span>
        <span class="nb">map</span>  <span class="p">{</span> <span class="nb">lc</span> <span class="p">}</span>
        <span class="nb">grep</span> <span class="p">{</span> <span class="sr">/[aeiou]/mix</span> <span class="p">}</span>
        <span class="nb">split</span> <span class="sr">//</span><span class="p">,</span> <span class="nv">$string</span><span class="p">;</span>
    <span class="k">for</span> <span class="k">my</span> <span class="nv">$i</span> <span class="p">(</span> <span class="mi">0</span> <span class="o">..</span> <span class="o">-</span><span class="mi">1</span> <span class="o">+</span> <span class="nb">length</span> <span class="nv">$string</span> <span class="p">)</span> <span class="p">{</span>
        <span class="k">my</span> <span class="nv">$c</span> <span class="o">=</span> <span class="nb">substr</span><span class="p">(</span> <span class="nv">$string</span><span class="p">,</span> <span class="nv">$i</span><span class="p">,</span> <span class="mi">1</span> <span class="p">);</span>
        <span class="k">my</span> <span class="nv">$v</span> <span class="o">=</span> <span class="nv">$c</span> <span class="o">=~</span> <span class="sr">/[aeiou]/mix</span> <span class="p">?</span> <span class="mi">1</span> <span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span> <span class="nv">$c</span> <span class="o">=~</span> <span class="sr">/[aeiou]/mix</span> <span class="p">)</span> <span class="p">{</span>
            <span class="k">my</span> <span class="nv">$n</span> <span class="o">=</span> <span class="nb">shift</span> <span class="nv">@vowels</span><span class="p">;</span>
            <span class="nv">$n</span> <span class="o">=</span> <span class="nb">uc</span> <span class="nv">$n</span> <span class="k">if</span> <span class="nv">$c</span> <span class="ow">eq</span> <span class="nb">uc</span> <span class="nv">$c</span><span class="p">;</span>
            <span class="nb">substr</span><span class="p">(</span> <span class="nv">$string</span><span class="p">,</span> <span class="nv">$i</span><span class="p">,</span> <span class="mi">1</span> <span class="p">)</span> <span class="o">=</span> <span class="nv">$n</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="nv">$string</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ./ch-2.pl 
Input:  $s = "Raku"
Output: "Ruka"

Input:  $s = "Perl"
Output: "Perl"

Input:  $s = "Julia"
Output: "Jaliu"

Input:  $s = "Uiua"
Output: "Auiu"

Input:  $s = "Dave"
Output: "Deva"

Input:  $s = "signatures"
Output: "segnutaris"

Input:  $s = "weekly challenge"
Output: "weekly challenge"
</code></pre></div></div>

<h4 id="if-you-have-any-questions-or-comments-i-would-be-glad-to-hear-it-ask-me-on-mastodon-or-make-an-issue-on-my-blog-repo">If you have any questions or comments, I would be glad to hear it. Ask me on <a href="https://mastodon.xyz/@jacobydave">Mastodon</a> or <a href="https://github.com/jacoby/jacoby.github.io">make an issue on my blog repo.</a></h4>]]></content><author><name>Dave Jacoby</name></author><summary type="html"><![CDATA[Welcome to Weekly Challenge #254! 254, the product of 2 and 127, is a semiprime number. It is deficient, in that the sum of its divisors is 130, which is less than itself.]]></summary></entry></feed>