aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Thompson <i@ry.ca>2019-11-02 18:07:25 -0600
committerRyan Thompson <i@ry.ca>2019-11-02 18:07:25 -0600
commited35b511e8ed24f1c6f0de037e08f74665c6d0cf (patch)
tree05063ab60ac6c356048d971d68a62bf2732aeb97
parent7a2acac4849ee76c96c510aa64d9fc4502854c0e (diff)
downloadperlweeklychallenge-club-ed35b511e8ed24f1c6f0de037e08f74665c6d0cf.tar.gz
perlweeklychallenge-club-ed35b511e8ed24f1c6f0de037e08f74665c6d0cf.tar.bz2
perlweeklychallenge-club-ed35b511e8ed24f1c6f0de037e08f74665c6d0cf.zip
Week 32 solutions
-rwxr-xr-xchallenge-032/ryan-thompson/perl5/ch-1.pl26
-rwxr-xr-xchallenge-032/ryan-thompson/perl5/ch-2.pl55
-rwxr-xr-xchallenge-032/ryan-thompson/perl6/ch-1.p620
3 files changed, 101 insertions, 0 deletions
diff --git a/challenge-032/ryan-thompson/perl5/ch-1.pl b/challenge-032/ryan-thompson/perl5/ch-1.pl
new file mode 100755
index 0000000000..3ec455ad1c
--- /dev/null
+++ b/challenge-032/ryan-thompson/perl5/ch-1.pl
@@ -0,0 +1,26 @@
+#!/usr/bin/env perl
+
+# Instance Count
+#
+# Ryan Thompson <rjt@cpan.org>
+
+use strict;
+use warnings;
+no warnings 'uninitialized';
+use List::Util qw< max >;
+
+# -csv must be first argument, in case you need to process a file named '-csv'
+# Usually I'd use Getopt::Long, but this is even simpler.
+my $csv = $ARGV[0] eq '-csv' ? shift : 0;
+
+my %count; # string => count
+chomp, $count{$_}++ while <>;
+
+# Pretty output is better than a lower constant on your complexity. :-)
+my $key_width = max map { length } keys %count;
+my $val_width = max map { length } values %count;
+my $fmt = $csv ? "%s,%d\n" : "%-${key_width}s %${val_width}d\n";
+
+# Sort by result count, then alphabetically by keyword
+printf $fmt, $_, $count{$_}
+ for sort { $count{$a} <=> $count{$b} || $a cmp $b } keys %count;
diff --git a/challenge-032/ryan-thompson/perl5/ch-2.pl b/challenge-032/ryan-thompson/perl5/ch-2.pl
new file mode 100755
index 0000000000..1d90fe363c
--- /dev/null
+++ b/challenge-032/ryan-thompson/perl5/ch-2.pl
@@ -0,0 +1,55 @@
+#!/usr/bin/env perl
+
+# ASCII Bar Chart
+#
+# I've added the optional "sort by" option, and then I went and added
+# negative numbers and auto-scaling to a user-specified --width for fun.
+#
+# Ryan Thompson <rjt@cpan.org>
+
+use 5.010;
+use strict;
+use warnings;
+use List::Util qw/min max/;
+use Math::Round;
+
+my %data = ( foo => 10, bar => 20, foobar => 50 );
+
+print_bar_graph_simple(\%data);
+say '';
+print_bar_graph({ %data, neg => -25 }, { char => '=', width => 50 });
+
+# Simple version. Auto-sizes the labels, that's about it.
+sub print_bar_graph_simple {
+ my ($data) = @_;
+
+ my $len = max map { length } keys %$data;
+ printf "%-${len}s | %s\n", $_, '#' x round($data->{$_})
+ for sort keys %$data;
+}
+
+# "Deluxe" version with scaling, custom bars, and negative number support
+# by_key: True = Sort by key, then value [Default: value, then key ]
+# width: Scale to total width, including labels [Default: undef (no scale)]
+# char: Character to use for bars in bar chart [Default: # ]
+sub print_bar_graph {
+ my ($data, $opts) = @_;
+
+ my $sort = $opts->{by_key}
+ ? sub { $a cmp $b || $data->{$a} <=> $data->{$b} }
+ : sub { $data->{$a} <=> $data->{$b} || $a cmp $b };
+
+ # Housekeeping for number scaling and label sizing
+ my $len = max map { length } keys %$data;
+ my $width = $opts->{width} ? $opts->{width} - $len - 1 : 0;
+ my $max = max $width, values %$data;
+ my $negmax = min 0, values %$data;
+ my $scale = $width ? $width / (abs($negmax) + 1 + $max) : 1;
+ my $negpad = round($scale * abs($negmax));
+
+ printf "%-${len}s %${negpad}s|%s\n", $_,
+ $data->{$_} < 0
+ ? ( $opts->{char} x round(abs($data->{$_}) * $scale), '')
+ : ('', $opts->{char} x round( $data->{$_} * $scale))
+ for sort $sort keys %$data;
+}
diff --git a/challenge-032/ryan-thompson/perl6/ch-1.p6 b/challenge-032/ryan-thompson/perl6/ch-1.p6
new file mode 100755
index 0000000000..7296f84dc3
--- /dev/null
+++ b/challenge-032/ryan-thompson/perl6/ch-1.p6
@@ -0,0 +1,20 @@
+#!/usr/bin/env perl6
+
+# Instance Count
+#
+# Same basic algorithm as the p5 version, just a little more Raku-ish.
+# We read a line at a time so we don't have to store all lines in RAM.
+#
+# Ryan Thompson <rjt@cpan.org>
+
+# Bit of a hack. Normal preference would be MAIN(Bool :$csv) or Getopt::Long
+my $csv = (@*ARGS[0] and @*ARGS[0] eq '-csv') ?? @*ARGS.shift !! False;
+
+my %count;
+%count{ $*ARGFILES.get }++ while ! $*ARGFILES.eof;
+
+my $key_width = %count. keys.race.map({.chars}).max;
+my $int_width = %count.values.race.map({.chars}).max;
+my $fmt = $csv ?? "%s,%s\n" !! "%-{$key_width}s %{$int_width}d\n";
+
+$fmt.printf(.key, .value) for %count.sort: { .value, .key };