CY's Take on The Weekly Challenge #131
If you want to challenge yourself on programming, especially on Perl and/or Raku, go to https://theweeklychallenge.org, code the latest challenges, submit codes on-time (by GitHub or email).
Do tell me, if I am wrong or you strongly oppose my statements!
It's time for challenges in Week #131 !
And here comes two nice tasks submitted by teammates.
Task 1: Consecutive Arrays
I like this task. Its simplicity makes it a perfect testing performance of showing the power of compactness of a language (for example, the Raku solutions "in a [Twitter] tweet" by Mr Markus Holzer) or learning a new language.
My code in Perl and Julia:
In Perl:
sub consec { my @a = @_; my @list = ([ $a[0] ],); for my $i (1..$#a) { if ($a[$i] == $a[$i-1] + 1) { push $list[-1]->@*, $a[$i]; } else { push @list, [$a[$i]]; } } return \@list; }
In Julia:
function consecutive(a) list = [ [ a[1] ], ] for i = 2:length(a) if a[i] == a[i-1]+1 push!(list[end], a[i]) else push!(list, [ a[i] ]) end end return list end
In Julia, it is required that elements of an array being the same type. (I don't know the technical term...) (Wrong.)
Also note that the array of Julia starts indexing from 1 instead of indexing from 0.
Since this is one of my early codes in Julia, I encountered some obstacles. It would be great to learn how to read the feedback of REPL in Julia or any interpreter/compiler of any programming languages for debugging.
Mentioning the usefulness of feedback, it is worth the time to note down my solution for Task 2.
Task 2: Find Pairs
The abundant choice of delimiters is a special feature of Perl.
It's fun to see how many symbols can be used as delimiters:
$ perl -E '$_ = "cba"; tr^abc^def^; say' fed $ perl -E '$_ = "cba"; tr$abc$def$; say' fed $ perl -E '$_ = "cba"; tr@abc@def@; say' fed $ perl -E '$_ = "cba"; tr+abc+def+; say' fed $ perl -E '$_ = "cba"; tr-abc-def-; say' fed $ perl -E '$_ = "cba"; tr&abc&def&; say' fed
Therefore the Task 2 code I start it with
my @open_uni = qw/ ( [ { < /; my @close_uni = qw/ ) ] } > /; my %partner = ( ')'=>'(', ']'=>'[', '}'=>'{', '>' => '<' ); my @neutral_uni = qw{ , . ? ! / \ }; push @neutral_uni, qw{ @ # $ & + - ^ * % " ' }; # dangerous zone
The given task statement does not state the practical side of the task and I guess it is about tidying the pairing of delimiting symbols. Hence I decide to run an extra mile, write something with warnings and/or feedbacks.
Like this (extracted from the final production):
Test Case 1b Delimiters : (){} Search String: for ($a..$b} (cannot_do_sth;} (( }} Warning: ( at position 4 may not close appropriately. Warning: } at position 11 may not be corresponding to an opening delimiter. Feedback: It is recommended that you check other delimiters as well.
Originally I ambitiously intended to write the code for multi-line strings! Time does not allow. Ooops.
For the ease of explanation, let us see the output of the final product first:
$ perl ch-2.pl '(){}**' '(*Hello*)' Delimiters : (){}** Search String: (*Hello*) (** **) ========================================= Example 1 Delimiters : ""[]() Search String: "I like (parens) and the Apple ][+" they said. "([" ")]" Warning: " at position 0 may not close appropriately. Warning: ] at position 31 may not be corresponding to an opening delimiter. Feedback: It is recommended that you check other delimiters as well. Example 2 Delimiters : **//<> Search String: /* This is a comment (in some languages) */ <could be a tag> /**/< /**/> Test Case 1a Delimiters : (){} Search String: for ($a..$b) {do_sth;} ({ )} Test Case 1b Delimiters : (){} Search String: for ($a..$b} (cannot_do_sth;} (( }} Warning: ( at position 4 may not close appropriately. Warning: } at position 11 may not be corresponding to an opening delimiter. Feedback: It is recommended that you check other delimiters as well. Test Case 2a Delimiters : (){}** Search String: ( ilovePerl()*) {bad;} ((*{ )*)} Warning: * at position 13 may not close appropriately. Warning: ) at position 14 may not be corresponding to an opening delimiter. Feedback: It is recommended that you check other delimiters as well. Test Case 2b Delimiters : (){}** Search String: (*ilovePerl()*) {good;} (*(*{ *)*)} Test Case 3 Delimiters : <> Search String: <html><head><title>HELLO</title></head></html> <<<<<< >>>>>> Test Case 4a Delimiters : **//\\ Search String: */layer/* *//* *//* Test Case 4b Delimiters : **//\\ Search String: */wrong layer*/ */*/ */*/ Warning: delimiter(s) do not open or close appropriately: Delimiters: * / * / Positions: 0 1 13 14
say "Example 2"; find_pair( [qw' ** // <> '], '/* This is a comment (in some languages) */ <could be a tag>' );
The implementation of find_pair is more than 100 lines so I just put part of it here.
sub find_pair { my %open_found; my %close_found; my %neutral_found; my @char = split //, $_[1]; my @delimiters = split //, (join "", $_[0]->@*); for my $pair (@{$_[0]}) { my $s_head = substr($pair, 0, 1); my $s_tail = substr($pair, 1, 1); $open_found{$s_head} = [] if any { $_ eq $s_head } (map {substr($_, 0, 1)} @open_uni); #... } for my $i (0..$#char) { my $c = $char[$i]; push $open_found{$c}->@*, $i if defined($open_found{$c}); #... } my @open_positions; my @close_positions; my @all_positions; for (values %open_found, values %neutral_found) { push @open_positions, $_->@*; } #... @all_positions = sort {$a<=>$b} @all_positions; my @stack; my @waiting_to_be_closed; # variable for warning message my $early_warn; # variable for warning message for my $p (@all_positions) { my $c = $char[$p]; if (defined($open_found{$c})) { push @stack, $c; push @waiting_to_be_closed, $p; } #... } if (!$early_warn && scalar @stack != 0 && !defined($close_found{$stack[-1]}) ) { say "Warning: delimiter(s) do not open or close appropriately:"; say "Delimiters: @stack"; say "Positions: ", "@waiting_to_be_closed"; } if ($early_warn) { say "Feedback: It is recommended that you check other ", "delimiters as well."; } say ""; }
Final note: I had thought to skip this task due to the constraint of time. After I finished it last night, I think it's worth the effort (but still can improve further... some ideas: e.g. using edit distance to give suggestions). If you have seen my Twitter, you probably know why I start to use Julia ‐ I gonna work on making math animations for a few months. This is going to be my first formal programming job! In addition, I got admitted to a part-time program in Information Technology ‐ I will start school in mid-Oct, having 9.5 hr of lecture time per week. However, like, for the heavy coding (in TWC tasks) of nearly 200 lines of code of Task 2, I feel difficult to write down the flow here, or comment the flow within codes. There is still large room of improvement for CY as a coder. Need to learn some time management or "energy management" in order to balance different aspects of my life. One of the obvious hurdles is in December, when the Advent of Code event gonna be held.
Stay alert and healthy! □
The image of the flat helix is made by me via Processing. I declare here that I release it as a public domain image.
Except from images and codes from other personnels, the content of this blogpost is released under a copyleft spirit. One may share (full or partial) content of this blogpost on other platform if you share it under the free and open content spirit.
link for CY's full codes: ch-1.pl, ch-1.jl, ch-2.pl
Contact on twitter: @e7_87.
Discuss via GitHub issues: here.
Email: fungcheokyin at gmail.com
Created Date: 26th September, 2021. Updated: 27th September, 2021.