PWC 180

PWC 180

This week saw two light challenges, which I was able to do in both Perl 5 and Raku despite being busy at work. I also did Challenge 2 in Julia, but not Challenge 1. Challenge 1 is a string-handling task for which Julia is not a typical choice.

Challenge 1 (First unique character)

The challenge here is to find the first unique character in a given string. 

The string is likely to be short (a long string would be unlikely to have unique characters, if naturally generated from a much smaller number of characters). So a two-loop solution should be efficient enough: 

  • one loop to count the occurrences of each character using a hash, and 
  • the second to loop through the characters again, checking the number of occurrences from the hash, and stopping at the first character for which the number of occurrences equals 1. 

A twist is that we are asked to return the index position of the character, not the character itself. 

I give my Perl 5 subroutine a somewhat retro flavor by just using a single localized symbol table entry '*s' for everything. The local scalar $s is assigned the string argument, @s is the array of characters from the string, %s is the hash used to store the count for each character, and $s again does double duty as a loop index in both loops. This leads to cool(?) snippets like:

if ($s{$s[$s]}==1) {...

(Darn, I just realized that I could have named the subroutine 's' too! Oh well.) 

My Raku code is similar, but without the package-variable cool(?)ness. Raku is full of siren-like temptations such as BagHashes etc., but I austerely ignored them and just ported my Perl 5 code.

As I mentioned, I did not try this in Julia, which is designed mainly for more STEM-y large-scale number-crunching tasks (though of course Julia can handle this simple task, as can other scripting languages. For example, here is a Julia script from Robert diCicco.)

For these challenges, I write scripts in Julia mainly to benchmark my Perl 5 and Raku scripts. That benchmarking role is not very useful for tasks like this.

Other contributions

There are some master craftsmen contributing to these challenges, so let me point to a couple of their efforts. Flavio Poletti  has a fast, efficient approach using a doubly-linked list, which would work even with very large strings that include Unicode, for example a corpus of Chinese text. E Choroba demonstrates several different ways to do it, including a very nice regex.  As Choroba shows, Perl (4, 5 or 6) is very versatile in such string handling tasks, I don't think there is anything else that can compete in this respect. There is even a ready-made function for this task in the List::MoreUtils package (List::MoreUtils::firstidx), as demonstrated by James Smith here.


Challenge 2 (trim)

Challenge  2 asks us to trim an array of numbers by removing items that are strictly less than a given integer say 'i'. The problem description says "less than or equal to", but the test examples originally given were consistent with "strictly less". I have gone with the original test examples. (Our good host corrected the examples later, but I had already submitted. I will stick with my solutions, it shouldn't really matter.)

In Perl 5, I use PDL which enables a concise solution via the "where" filter method. Here is a snippet:

return $n->where($n >= $i); 

In Raku, an equally concise solution is available via grep. A snippet:

@n.grep({$_ >= $i}).say;

That syntax is directly inherited from Perl 5, in which one can do much the same thing with left-branching instead of right-branching syntax (say grep {...} @n).

In Julia, an equally concise solution is available via its equivalent of the PDL 'where' filter. A snippet:

return n[n .>= i]

The .>= operator is an element-wise greater-than-or-equal-to comparison. 

Tempting to try these as one-liners in all three languages. But from the task specification, it seems better to write a subroutine/function.

Here is my Perl 5 script.


Popular posts from this blog

PWC 183

PWC 182

PWC 177