diff options
| author | drbaggy <js5@sanger.ac.uk> | 2022-05-27 05:52:42 +0100 |
|---|---|---|
| committer | drbaggy <js5@sanger.ac.uk> | 2022-05-27 05:52:42 +0100 |
| commit | 429436f38cf432087bc3144974be05c6056ac934 (patch) | |
| tree | d6c8ca9c56abf67c88217001723e7744216067db | |
| parent | 23f495993f7501cc15f4daa06cc2e995cc172d51 (diff) | |
| parent | 681766cb864c3bb6116c8edc06f6f156e3c554b0 (diff) | |
| download | perlweeklychallenge-club-429436f38cf432087bc3144974be05c6056ac934.tar.gz perlweeklychallenge-club-429436f38cf432087bc3144974be05c6056ac934.tar.bz2 perlweeklychallenge-club-429436f38cf432087bc3144974be05c6056ac934.zip | |
Merge branch 'master' of github.com:drbaggy/perlweeklychallenge-club
| -rw-r--r-- | challenge-166/james-smith/README.md | 101 | ||||
| -rw-r--r-- | challenge-166/james-smith/blog.txt | 1 |
2 files changed, 93 insertions, 9 deletions
diff --git a/challenge-166/james-smith/README.md b/challenge-166/james-smith/README.md index 222ff79205..23c0dda58b 100644 --- a/challenge-166/james-smith/README.md +++ b/challenge-166/james-smith/README.md @@ -20,9 +20,25 @@ https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-166/ja Now I've concentrated on challenge 2 this week but here is some of my code for Challenge 1 ## Solution -Find all hex words... +Find all hex words, this generates all words, with options for adding filters - to +restrict the number of numbers - to only letters or all letters. By commenting/uncommenting +the filter lines.... I have added one more mapping that is in standard use which is +`g` -> `9` {others use `6` but it still works} + ```perl +while(<>) { + chomp; + next unless m{^[abcdefoilstg]+$}; + my $t = $_; + my $N = tr/oilstg/011579/; + next if $N < length $_; + #next if $N > 0; + #next if $N > 15; + warn "$N\t$t\t$_\n" if $N == length $_; + $words->[length $_]{$N}{$t}="$_ (".hex($_).")"; +} +print Dumper( $words ); ``` ## Some observations @@ -33,7 +49,7 @@ Find all hex words... dissociabilities 0x d155 0c1a b111 71e5 (15,083,975,835,726,737,893) lactobacillaceae 0x 1ac7 0bac 111a ceae ( 1,929,523,799,000,796,846) ``` -Can add (if we include the g->9 mapping {could also do g->6}): +Can add (if we include the g->9 mapping): ``` silicoflagellate 0x 5111 c0f1 a9e1 1a7e ( 5,841,662,335,845,997,182) ``` @@ -96,6 +112,7 @@ If we include the g->9 mapping we can have: ``` glossologists 0x 0000 91055 0109 1575 ( 2,551,232,066,033,013) ``` + # Challenge 2 - k-diff ## The solution @@ -128,6 +145,10 @@ The simplest approach is to use 3/4. ### Finding a complete list of different filenames +We collect a unique list of filenames, by putting them as the keys of a hash. We +could do this with a map - but it is useful to keep track of the number of times +we see each file. + ```perl my @paths = sort keys %directories; my %filename_counts; @@ -136,8 +157,22 @@ The simplest approach is to use 3/4. } ``` +### Compute the length of the longest directory or filename + +For the output we will want to pretty print it - and so need to work out the width +of the columns - this is a simple loop over the directories and filenames. +```perl + for ( @paths, keys %filename_counts ) { + $length = length $_ if length $_ > $length; + } +``` ### Build templates for printing page horizontal line, sprintf table of heading/contents +We draw the horizontal line three times, so it is useful to keep a copy of it, we +in the code also need a template to sprintf the header and the body of the table. +So we generate these now. We use the length we computed above to compute the runs of +characters needed. + ```perl my $HORIZONTAL_LINE = join '-' x ( $length+2 ), ('+') x (1+@paths); my $TEMPLATE = '|' . " %-${length}s |" x @paths; @@ -149,7 +184,22 @@ The simplest approach is to use 3/4. ### Workout what to print and printing -``perl +This loops through the unique filenames we stored earlier. Then +for each filename we first check that it is present in all lists. +If it is we remove it and go onto the next filename. As we kept +counts of each filename this is as easy as checking that the +count is the same as the number of directories - this is the +first if in the loop. + +We then loop through each column - if the filename is present +we shift it off and add it to the column array, if not we just +push a space onto the column array. Note we have to check that +their are entries left (*i.e.* we have got to the end of the +files in the directory otherwise it will throw a warning of +undefined value). Once we use this array we use the template +we produced above to print it. + +```perl ## map({$u{$F=$_}<@p?sprintf$T,map{($d{$_}[0]//'')ne$F?'': ## shift@{$d{$_}}}@p:map{shift@{$d{$_}};()}@p}sort keys%u) for my $filename ( sort keys %filename_counts ) { @@ -169,12 +219,18 @@ The simplest approach is to use 3/4. } ``` -## Just a minor block at the end -say $1 +### Add the last line... + +We print the bottom of the table: + +```perl +say $1; +``` + ## The full code (with comments) ```perl -sub z_diff { +sub k_diff { ## Declare variables @@ -270,10 +326,10 @@ sub z_diff { I started with a "simple" compact version of the code and then came discussions with Eliza on the Perl Programmers Facebook group and things -slowly got smaller. A few bytes at a time... +slowly got smaller. A few bytes at a time to the 354 byte: ```perl -sub z{my($l,$F,%d,%u,$T,$H)=0;(@_=split'/'),push@{$d{$_[0]}},-d?"$_[1]/":$_[1] +sub k{my($l,$F,%d,%u,$T,$H)=0;(@_=split'/'),push@{$d{$_[0]}},-d?"$_[1]/":$_[1] for<*/*>;$u{$_}++for map{@{$d{$_}}}my@p=sort keys%d;$l<length?$l=length:1for@p, @_=keys%u;say for$H=join('-'x($l+2),('+')x(1+@p)),sprintf($T="| %-${l}s "x@p.'|' ,@p),$H,map({$u{$F=$_}<@p?sprintf$T,map{($d{$_}[0]//'')ne$F?'':shift@{$d{$_}}}@p @@ -293,10 +349,37 @@ for<*/*>;$u{$_}++for map{@{$d{$_}}}my@p=sort keys%d;$l<length?$l=length:1for@p, ``` **Notes** + - We replace many of the loops and conditionals with `map`s and `_?_:_` - Where we use `$_` there are numerous function calls which use this when no parameter is passed - in this case `length`, `split`, `-d`. - When a "string" starts with a number than has a letter in it treats it as if to add a space between the number and the rest of the string so we can rewrite - `1 for $condition` as `1for$condition`. + `1 for @array` as `1for@array`. - we don't need to do `sort blob '*/*'` or `sort <*/*>` as for all "current" versions of Perl we can assume that perl does this for us. + +## Coda - taking the brakes off... + +For ultimate compactness we can remove the function overhead off, turn off both +`strict` and `warnings`. We can reduce this to either 317 bytes (or 315 bytes) + +```perl +(@_=split'/'),push@{$d{$_[0]}},-d?"$_[1]/":$_[1]for<*/*>;$u{$_}++for map{@{$d{$_}}}my@p=sort keys%d;$l<length?$l=length:1for@p,@_=keys%u;print$H=join('-'x($l+2),('+')x@p,'+ +'),sprintf($T="| %-${l}s "x@p.'| +',@p),$H,map({$u{$F=$_}<@p?sprintf$T,map{$d{$_}[0]ne$F?'':shift@{$d{$_}}}@p:map{shift@{$d{$_}};()}@p}sort@_),$H +``` +This is the 317 byte version - we could reduce it to 315 bytes by replacing +`print` with `say` again... But ultimately that makes the execution more bytes. + +Command line with `print`: + +```perl +perl ch-2-ns.pl +``` + +Command line with `say` + +```perl +perl -M5.10.0 ch-2-ns.pl +``` +So to save 2 bytes we use 9 more to run the command... of course you could just run it as a 1-liner on the command line (with the -E) but that would just be silly! diff --git a/challenge-166/james-smith/blog.txt b/challenge-166/james-smith/blog.txt new file mode 100644 index 0000000000..50ad28ac41 --- /dev/null +++ b/challenge-166/james-smith/blog.txt @@ -0,0 +1 @@ +https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-166/james-smith |
