From ed35b511e8ed24f1c6f0de037e08f74665c6d0cf Mon Sep 17 00:00:00 2001 From: Ryan Thompson Date: Sat, 2 Nov 2019 18:07:25 -0600 Subject: Week 32 solutions --- challenge-032/ryan-thompson/perl5/ch-1.pl | 26 +++++++++++++++ challenge-032/ryan-thompson/perl5/ch-2.pl | 55 +++++++++++++++++++++++++++++++ challenge-032/ryan-thompson/perl6/ch-1.p6 | 20 +++++++++++ 3 files changed, 101 insertions(+) create mode 100755 challenge-032/ryan-thompson/perl5/ch-1.pl create mode 100755 challenge-032/ryan-thompson/perl5/ch-2.pl create mode 100755 challenge-032/ryan-thompson/perl6/ch-1.p6 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 + +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 + +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 + +# 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 }; -- cgit