PWC 184

PWC 184

Both the tasks for this week have narrowly defined input requirements. I don't write a function to handle them. I want to avoid input validation and error handling chores, and any self-respecting function needs both. I present throwaway scripts or one-liners with the inputs explicitly written into the script or ARGV. 

Challenge 1 (Sequence number)

We are given a list of strings, each one formatted as two lower-case alphabets (/[a-z]/) followed by 4  numeric characters (/[0-9/), e.g.,  ('ab1234', 'cd5678', 'ef1342'). We are asked to replace the starting alphabets with a two-digit string of numbers indicating their position in the list starting with zero, e.g., ('001234', '015678', '021342').

I do this with one-liners in Perl 5, Raku and Julia.

Perl 5:

perl -e 'my $ctr=0; for my $x ("00" .. "99") {print $x . substr($ARGV[$ctr++],2,4) . " "; last if $ctr >= @ARGV;} print "\n";' 'ab1234' 'cd5678' 'ef1342'

In Perl 5 (or Raku), we can loop through the strings "00" .. "99". It's then just a matter of prepending each string to the last 4 digits of each list entry, retrieved via substr.

I used a separate counter $ctr from the loop counter $x to move through the ARGV list.

Raku:

raku -e 'my $ctr=0; for ("00" .. "99") -> $x {print $x ~ @*ARGS[$ctr++].substr(2,4) ~ " "; last if $ctr >= @*ARGS }; print "\n";' 'ab1234' 'cd5678' 'ef1342'

This is a literal translation of my Perl 5 one-liner.

Julia:

julia -e 'using Printf; ctr=0; for mystring in ARGS; global ctr; @printf "%02i" ctr; print(SubString(mystring,3,6));print(" ");ctr+=1;end;println("")' 'ab1234' 'cd5678' 'ef1342'

In Julia, we use the Printf standard library,  and in particular the @printf macro.

@printf "%02i" ctr

prints ctr formatted as a zero-padded integer with width 2. Apart from this, our logic is like Perl 5 using Julia's built-in SubString function as a substitute for substr.

My Perl 5 one-liner runs in 0.01 seconds, my Raku one-liner in 0.35 seconds, and Julia is a bit slower at 0.40 seconds (it starts up slowly).

Other contributors (wow!)

As usual, looking at other contributors' solutions is humbling.  Several contributors have exploited the fact that the "++" operator can be used to step through the range "00" .. "99", in Perl 5 as well as Raku. As an example, here is Kjetil Skotheim with the lovely (Perl 5):

my $seq='00'; say s/../$seq++/er for @ARGV;

Here it is as a Raku one-liner.

raku -e 'my $seq="00"; @*ARGS.map({S/../{$seq++}/}).say' 'ab1234' 'cd5678' 'ef1342'

Challenge 2

We are given lists of strings, where each string is a stringified list of single space-separated characters that match /[a-z]/ or /[0-9]/. For each string, we are supposed to separate the numeric characters into one array and the alpha characters into another. Then we push the array of numeric characters into a bigger array containing arrays of numerics derived from other strings in the list, and ditto for the alpha array.

To give an example (the test example), given an input of ('a 1 2 b 0', '3 c 4 d'), we should return the pair of arrays of arrays: (['a','b'],['c','d']) and ([1,2],[3,4]).

In Perl 5, I loop through the list of strings, and then for each string loop through the characters, tossing them into the designated array for numbers or for alpha characters as appropriate. We use a regex to identify numeric vs alpha. 

I then toss the numeric and alpha arrays (if non-empty) into the bigger arrays that I prepared earlier to collect them.  Finally, I loop through these bigger arrays to print them out.

Raku is a literal translation. There is no need to write a loop to print out the array of arrays. Say does that directly.

In Julia I use the same logic . Instead of using a regex to identify alpha vs numeric characters, I use the membership operator in.  

if char in '0':'9'

Printing is also direct, like Raku.

Here is my Julia script.

Here is my Raku script.

Here is my Perl 5 script.

Julia runs in around 0.9 seconds, Raku in around 0.5 seconds, and Perl 5 in around 0.01 seconds. Julia is slower partly because of slow startup. My design is also inefficient because of the global variables I set up outside the loop (the input list, and the two arrays of arrays set up outside the loop). Recommended best practice is to avoid global variables.

"Global" does not mean quite the same thing in Julia as it does in Perl 5. A Julia global variable is more like a Perl-5 "my" variable declared outside any block or subroutine (file-scope lexical). Here is the Julia doc on variable scope.

Comments

Popular posts from this blog

PWC 258

PWC 253

PWC 249