aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2022-05-30 00:44:59 +0100
committerGitHub <noreply@github.com>2022-05-30 00:44:59 +0100
commit4139dd865e502ce4e192389fa58f41811ba3d4e7 (patch)
treea5008eabc0ad86dc5c5d61ddf424417aacf5a604
parent45dee6cd065bdb515f9ea33ee8aa093dc01287e5 (diff)
parentaf65953d0f086f5f03fa0f618525e6c61c3332e7 (diff)
downloadperlweeklychallenge-club-4139dd865e502ce4e192389fa58f41811ba3d4e7.tar.gz
perlweeklychallenge-club-4139dd865e502ce4e192389fa58f41811ba3d4e7.tar.bz2
perlweeklychallenge-club-4139dd865e502ce4e192389fa58f41811ba3d4e7.zip
Merge pull request #6178 from drbaggy/master
oopses
-rw-r--r--challenge-166/james-smith/README.md155
-rw-r--r--challenge-166/james-smith/perl/ch-2.pl36
2 files changed, 71 insertions, 120 deletions
diff --git a/challenge-166/james-smith/README.md b/challenge-166/james-smith/README.md
index 82352a1088..4cc3055242 100644
--- a/challenge-166/james-smith/README.md
+++ b/challenge-166/james-smith/README.md
@@ -135,14 +135,6 @@ Each have advantages/disadvantages:
The simplest approach is to use 3/4.
-```perl
- my %directories;
- for my $path ( sort blob '*/*' ) {
- my( $dir, $file ) = split m{/}, $path;
- push @{ $directories{$dir} }, -d $path ? "$file/" : $file;
- }
-```
-
### Finding a complete list of different filenames
We collect a unique list of filenames, by putting them as the keys of a hash. We
@@ -150,11 +142,14 @@ 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;
- for my $path ( @paths ) {
- $filename_counts{ $_ }++ for @{$directories{ $path }};
+ my( %directories, %filenames );
+ for( sort <*/*> ) {
+ my( $dir, $file ) = split m{/}, $_;
+ $directories{$dir}=1;
+ $file.='/' if -d $_;
+ $filenames{ $file }{ $dir } = 1;
}
+ my @paths = sort keys %directories;
```
### Compute the length of the longest directory or filename
@@ -162,7 +157,8 @@ we see each file.
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 ) {
+ my $length = 0;
+ for ( @paths, keys %filenames ) {
$length = length $_ if length $_ > $length;
}
```
@@ -192,25 +188,15 @@ 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.
+we display it o/w we display a blank string.
```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 ) {
- if( $filename_counts{ $filename } == @paths ) {
- shift @{$_} for values %directories;
- next;
- }
+ for my $filename ( sort keys %filenames ) {
+ next if @paths == keys %{$filenames{$filename}};
my @columns;
for (@paths) {
- if( @{$directories{$_}} && $directories{$_}[0] eq $filename ) {
- push @columns, shift @{$directories{$_}};
+ if( exists $filenames{$filename}{$_} ) {
+ push @columns, $filename;
} else {
push @columns, '';
}
@@ -231,84 +217,37 @@ say $1;
```perl
sub k_diff {
-
- ## Declare variables
-
- ## my($l,%d,$F,@p,%u,$T,$H)=0;
- my( $length, %directories, %filename_counts )=0;
-
- ## Read all sub-directories containing files and store
- ## in data structure as a hash of ordered arrays
- ## For directories add a trailing slash...
-
- ## (@_=split/\//),push@{$d{$_[0]}},-d$_?"$_[1]/":$_[1]for sort<*/*>;
- for my $pat ( sort blob '*/*' ) {
- my( $dir, $file ) = split m{/}, $path;
- push @{ $directories{$dir} }, -d $path ? "$file/" : $file;
+ ## my($l,%d,%u)=0;
+ my( $length, %directories, %filenames )=0;
+
+ ## /\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*>
+ for( sort <*/*> ) {
+ my( $dir, $file ) = split m{/}, $_;
+ $directories{$dir}=1;
+ $file.='/' if -d $_;
+ $filenames{ $file }{ $dir } = 1;
}
- ## Get out an ordered list of directories...
-
- ## $u{$_}++for map{@{$d{$_}}}@p=sort keys%d;
+ ## $l<length?$l=length:1for(my@p=sort keys%d),@_=keys%u
my @paths = sort keys %directories;
-
- ## Find the length of the longest directory name, and
- ## keep a record of the number of times each filename
- ## has been seen (also gives list of all unique filenames)
-
- for my $path ( @paths ) {
- $filename_counts{ $_ }++ for @{$directories{$path}};
- }
-
- ## Now find the length of the longest filename or directory name
- ## This gives us the column widths for the pretty display...
-
- ## (length$_>$l)&&($l=length$_)for@p,keys%u;
- for ( @paths, keys %filename_counts ) {
+ for ( @paths, keys %filenames ) {
$length = length $_ if length $_ > $length;
}
- ## Generate the ASCII code for a horizontal bar in the table
- ## and a template for sprintf for the rows of the table
-
+ ## say$a=join('-'x$l,('+--')x@p,"+\n"),sprintf($b="| %-${l}s "x@p."|\n",@p),$a,
my $HORIZONTAL_LINE = join '-' x ( $length+2 ), ('+') x (1+@paths);
my $TEMPLATE = '|' . " %-${length}s |" x @paths;
-
- ## Draw the header {directory names} of the table....
-
- ## say for$H=join('-'x($l+2),('+')x(1+@p)),
- ## sprintf($T='|'." %-${l}s |"x@p,@p),$H,
say $HORIZONTAL_LINE;
say sprintf $TEMPLATE, @paths;
say $HORIZONTAL_LINE;
- ## Now draw the body - we loop through each of the unique filenames
- ## and see whether it is in all 4 columns (in which case we skip)
- ## otherwise we look to see which entries are present in each
- ## directory and show those....
-
- ## 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 ) {
-
- ## If we have seen the file in all directories - we remove
- ## it from all directory lists {and do nothing}
-
- if( $filename_counts{ $filename } == @paths ) {
- shift @{$_} for values %directories;
- next;
- }
-
- ## If we haven't we loop through the rows if
- ## the first entry is the file then we push it
- ## on the list to print {and remove it from the directory list}
- ## if not we just push an empty string to the
- ## list
-
+ ## map({//;@p-%{$u{$'}}?sprintf$b,map{$u{$'}{$_}?$':''}@p:()}sort@_)
+ for my $filename ( sort keys %filenames ) {
+ next if @paths == keys %{$filenames{$filename}};
my @columns;
for (@paths) {
- if( @{$directories{$_}} && $directories{$_}[0] eq $filename ) {
- push @columns, shift @{$directories{$_}};
+ if( exists $filenames{$filename}{$_} ) {
+ push @columns, $filename;
} else {
push @columns, '';
}
@@ -316,9 +255,7 @@ sub k_diff {
say sprintf $TEMPLATE, @columns;
}
- ## Finally print out the bottom line
-
- ## $H
+ ## $a
say $HORIZONTAL_LINE;
}
```
@@ -326,24 +263,23 @@ sub k_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 to the 272 byte:
+slowly got smaller. A few bytes at a time to the 259 bytes:
```perl
-sub x{my($l,$F,%d,%u,@p)=0;/\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*>;$l<length?$l=
-length:1for(@p=sort keys%d),@_=keys%u;print$a=join('-'x$l,('+--')x@p,"+\n"),
-sprintf($b="| %-${l}s "x@p."|\n",@p),$a,map({$l=$_;@p>keys%{$u{$l}}?sprintf$b,
-map{$u{$l}{$_}?$l:''}@p:()}sort@_),$a}
+sub z{my($l,%d,%u)=0;/\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*>;$l<length?$l=length
+:1for(my@p=sort keys%d),@_=keys%u;say$a=join('-'x$l,('+--')x@p,"+\n"),sprintf($b
+="| %-${l}s "x@p."|\n",@p),$a,map({//;@p-%{$u{$'}}?sprintf$b,map{$u{$'}{$_}?$':
+''}@p:()}sort@_),$a}
```
-**or** if we "allow" return characters inside strings - this is 270 bytes of
+**or** if we "allow" return characters inside strings - this is 257 bytes of
perly goodness...
```perl
-sub z{my($l,$F,%d,%u,@p)=0;/\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*>;$l<length?$l=
-length:1for(@p=sort keys%d),@_=keys%u;print$a=join('-'x$l,('+--')x@p,'+
+sub z{my($l,%d,%u)=0;/\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*>;$l<length?$l=length
+:1for(my@p=sort keys%d),@_=keys%u;say$a=join('-'x$l,('+--')x@p,'+
'),sprintf($b="| %-${l}s "x@p.'|
-',@p),$a,map({$l=$_;@p>keys%{$u{$l}}?sprintf$b,map{$u{$l}{$_}?$l:''}@p:()}sort@_
-),$a}
+',@p),$a,map({//;@p-%{$u{$'}}?sprintf$b,map{$u{$'}{$_}?$':''}@p:()}sort@_),$a}
```
**Notes**
@@ -355,11 +291,16 @@ length:1for(@p=sort keys%d),@_=keys%u;print$a=join('-'x$l,('+--')x@p,'+
`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.
-
+ - Rather than using `split /\//`, we use the match operator `/\//` in one place
+ and `//` in another to split - the first half goes in `$`` and the second half
+ in `$'`.
+ - When using `//` this just copies `$_` into `$'`.
+ - if you subtract a hash in scalar context then it subtracts the numbers of keys.
+ Sp we can compute the number ot times a file is missing by doing `@p-%u`.
## 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)
+`strict` and `warnings`. We can reduce this to either 233 bytes (or 231 bytes)
```perl
/\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*>;$l<length?$l=length:1for(@p=sort keys%d),@_=keys%u;print$a=join('-'x$l,('+--')x@p,'+
diff --git a/challenge-166/james-smith/perl/ch-2.pl b/challenge-166/james-smith/perl/ch-2.pl
index 60462a45fd..ae6742d30e 100644
--- a/challenge-166/james-smith/perl/ch-2.pl
+++ b/challenge-166/james-smith/perl/ch-2.pl
@@ -11,7 +11,8 @@ use Data::Dumper qw(Dumper);
# 1 2 3 4 5 6 7 8 9
say 'Super compact'; x(); say '';
say 'Super compact'; z(); say '';
-say 'No comments'; z_diff_no_comments(); say '';
+say 'Super compact'; g(); say '';
+#say 'No comments'; z_diff_no_comments(); say '';
exit;
say 'Original - fake data'; k_diff( data() ); say '';
@@ -146,20 +147,29 @@ sub z_diff_no_comments {
say $HORIZONTAL_LINE;
}
-## Merging the fetch/parse into the a single function gives us just 265 bytes
-## of perlly goodness {258 without the fn call overhead}
+## Merging the fetch/parse into the a single function gives us just 259 bytes
+## of perlly goodness {252 without the fn call overhead}
#23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789#
-sub x{my($l,$F,%d,%u,@p)=0;/\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*>;$l<length?$l=
-length:1for(@p=sort keys%d),@_=keys%u;print$a=join('-'x$l,('+--')x@p,"+\n"),
-sprintf($b="| %-${l}s "x@p."|\n",@p),$a,map({//;@p-%{$u{$'}}?sprintf$b,map{$u{$'
-}{$_}?$':''}@p:()}sort@_),$a}
+sub g{my($l,%d,%u)=0;/\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*>;$l<length?$l=length
+:1for(my@p=sort keys%d),@_=keys%u;say$a=join('-'x$l,('+--')x@p,"+\n"),sprintf($b
+="| %-${l}s "x@p."|\n",@p),$a,map({//;@p-%{$u{$'}}?sprintf$b,map{$u{$'}{$_}?$':
+''}@p:()}sort@_),$a}
+
+sub x{
+ my($l,%d,%u)=0;
+ /\//,$u{$'.'/'x-d}{$d{$`}=$`}++ for <*/*>;
+ $l<length?$l=length:1 fo r(my@p=sort keys%d), @_=keys%u;
+ say $a=join( '-'x$l,('+--')x@p,"+\n" ),
+ sprintf( $b="| %-${l}s "x@p."|\n", @p ),
+ $a,
+ map( {//;@p-%{$u{$'}}?sprintf$b,map{$u{$'}{$_}?$':''}@p:() } sort @_ ),
+ $a
+}
-## 263 bytes (256 without fn overhead)
+## 257 bytes (250 without fn overhead)
#23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789#
-sub z{my($l,$F,%d,%u,@p)=0;/\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*>;$l<length?$l=
-length:1for(@p=sort keys%d),@_=keys%u;print$a=join('-'x$l,('+--')x@p,'+
+sub z{my($l,%d,%u)=0;/\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*>;$l<length?$l=length
+:1for(my@p=sort keys%d),@_=keys%u;say$a=join('-'x$l,('+--')x@p,'+
'),sprintf($b="| %-${l}s "x@p.'|
-',@p),$a,map({//;@p-%{$u{$'}}?sprintf$b,map{$u{$'}{$_}?$':''}@p:()}sort@_
-),$a}
-
+',@p),$a,map({//;@p-%{$u{$'}}?sprintf$b,map{$u{$'}{$_}?$':''}@p:()}sort@_),$a}