aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrbaggy <js5@sanger.ac.uk>2022-05-27 05:52:42 +0100
committerdrbaggy <js5@sanger.ac.uk>2022-05-27 05:52:42 +0100
commit429436f38cf432087bc3144974be05c6056ac934 (patch)
treed6c8ca9c56abf67c88217001723e7744216067db
parent23f495993f7501cc15f4daa06cc2e995cc172d51 (diff)
parent681766cb864c3bb6116c8edc06f6f156e3c554b0 (diff)
downloadperlweeklychallenge-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.md101
-rw-r--r--challenge-166/james-smith/blog.txt1
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