aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2019-11-03 15:28:08 +0000
committerGitHub <noreply@github.com>2019-11-03 15:28:08 +0000
commitdb600416f294a2abed5c0687aaa88ac429fa828e (patch)
tree4d4fa58efe7bb374ec59062951ba3275842cb786
parentae7d3579e987a745a828d2ef17ff125b5bb1b788 (diff)
parentf070d686a17e6cc6735dfd45e7b0c9a760851948 (diff)
downloadperlweeklychallenge-club-db600416f294a2abed5c0687aaa88ac429fa828e.tar.gz
perlweeklychallenge-club-db600416f294a2abed5c0687aaa88ac429fa828e.tar.bz2
perlweeklychallenge-club-db600416f294a2abed5c0687aaa88ac429fa828e.zip
Merge pull request #882 from PerlMonk-Athanasius/branch-for-challenge-032
Perl 5 & 6 solutions to Tasks 1 & 2 of Challenge #032
-rw-r--r--challenge-032/athanasius/perl5/ch-1.pl167
-rw-r--r--challenge-032/athanasius/perl5/ch-2.pl111
-rw-r--r--challenge-032/athanasius/perl6/ch-1.p6123
-rw-r--r--challenge-032/athanasius/perl6/ch-2.p6101
4 files changed, 502 insertions, 0 deletions
diff --git a/challenge-032/athanasius/perl5/ch-1.pl b/challenge-032/athanasius/perl5/ch-1.pl
new file mode 100644
index 0000000000..bda494dc33
--- /dev/null
+++ b/challenge-032/athanasius/perl5/ch-1.pl
@@ -0,0 +1,167 @@
+#!perl
+
+################################################################################
+=comment
+
+Perl Weekly Challenge 032
+=========================
+
+Task #1
+-------
+Contributed by Neil Bowers
+
+Count instances
+
+Create a script that either reads standard input or one or more files specified
+on the command-line. Count the number of times and then print a summary, sorted
+by the count of each entry.
+
+So with the following input in file example.txt
+
+ apple
+ banana
+ apple
+ cherry
+ cherry
+ apple
+
+the script would display something like:
+
+ apple 3
+ cherry 2
+ banana 1
+
+For extra credit, add a -csv option to your script, which would generate:
+
+ apple,3
+ cherry,2
+ banana,1
+
+=cut
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2019 PerlMonk Athanasius #
+#--------------------------------------#
+
+# Assumption: Data is to be treated as case-sensitive
+
+use strict;
+use warnings;
+use Const::Fast;
+use Getopt::Long;
+
+const my $USAGE =>
+ "USAGE: perl $0 Read from standard input\n" .
+ " perl $0 --file <Str>... Read from file(s)\n" .
+ " perl $0 <Str>... Read from the command line\n\n" .
+ "Options:\n" .
+ " --csv Generate output in CSV format\n" .
+ " --help Print usage details and exit\n";
+
+BEGIN
+{
+ $| = 1;
+ print "\n";
+}
+
+#===============================================================================
+MAIN:
+#===============================================================================
+{
+ my ($csv, $data, $help) = read_data();
+
+ if ($help)
+ {
+ print $USAGE;
+ }
+ else
+ {
+ # Count the entries
+
+ my %count;
+ ++$count{$_} for @$data;
+
+ # Sort keys by count: highest count first, equal counts in lexicographi-
+ # cal order. Adapted from:
+ # https://perldoc.perl.org/5.30.0/perlfaq4.html#How-do-I-sort-a-hash-
+ # (optionally-by-value-instead-of-key)%3f
+
+ my @keys = sort
+ {
+ $count{$b} <=> $count{$a} # Descending
+ ||
+ $a cmp $b # Lexicographical
+
+ } keys %count;
+
+ my $delimiter = $csv ? ',' : "\t";
+
+ printf "%s%s%d\n", $_, $delimiter, $count{$_} for @keys;
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub read_data
+#-------------------------------------------------------------------------------
+{
+ my ($csv, $data, @files, $help);
+
+ GetOptions
+ (
+ csv => \$csv,
+ 'file=s{1,}' => \@files,
+ help => \$help,
+
+ ) or die $USAGE;
+
+ unless ($help)
+ {
+ if (scalar @files > 0)
+ {
+ $data = read_files(@files);
+ }
+ elsif (scalar @ARGV > 0)
+ {
+ $data = [ @ARGV ];
+ }
+ else
+ {
+ printf "Enter data (^%s to stop):\n", $^O eq 'MSWin32' ? 'Z' : 'D';
+
+ push @$data, split /\s+/ while <STDIN>;
+ }
+ }
+
+ return ($csv, $data, $help);
+}
+
+#-------------------------------------------------------------------------------
+sub read_files
+#-------------------------------------------------------------------------------
+{
+ my @data;
+ my @files = @_;
+
+ for my $file (@files)
+ {
+ my $text = '';
+
+ open my $fh, '<', $file
+ or die "Cannot open file '$file' for reading, stopped";
+
+ {
+ local $/;
+ $text = <$fh>;
+ }
+
+ close $fh
+ or die "Cannot close file '$file', stopped";
+
+ push @data, split /\s+/, $text;
+ }
+
+ return \@data;
+}
+
+################################################################################
diff --git a/challenge-032/athanasius/perl5/ch-2.pl b/challenge-032/athanasius/perl5/ch-2.pl
new file mode 100644
index 0000000000..f50be88192
--- /dev/null
+++ b/challenge-032/athanasius/perl5/ch-2.pl
@@ -0,0 +1,111 @@
+#!perl
+
+################################################################################
+=comment
+
+Perl Weekly Challenge 032
+=========================
+
+Task #2
+-------
+Contributed by Neil Bowers
+
+ASCII bar chart
+
+Write a function that takes a hashref where the keys are labels and the values
+are integer or floating point values. Generate a bar graph of the data and dis-
+play it to stdout.
+
+The input could be something like:
+
+ $data = { apple => 3, cherry => 2, banana => 1 };
+ generate_bar_graph($data);
+
+And would then generate something like this:
+
+ apple | ############
+ cherry | ########
+ banana | ####
+
+If you fancy then please try this as well: (a) the function could let you speci-
+fy whether the chart should be ordered by (1) the labels, or (2) the values.
+
+=cut
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2019 PerlMonk Athanasius #
+#--------------------------------------#
+
+use strict;
+use warnings;
+use Const::Fast;
+use List::Util qw( max );
+
+const my $BAR_CHARACTER => '#';
+const my $BAR_MULTIPLIER => 4;
+const my $ORDER_BY_LABELS => 0;
+const my $ORDER_BY_VALUES => 1;
+
+BEGIN
+{
+ $| = 1;
+ print "\n";
+}
+
+#===============================================================================
+MAIN:
+#===============================================================================
+{
+ my $data =
+ {
+ cherry => 2,
+ apple => 1.5,
+ banana => 3,
+ watermelon => 2,
+ mango => 3.8,
+ };
+
+ my $graph = generate_bar_graph($data, $ORDER_BY_LABELS);
+ print $graph, "\n";
+
+ $graph = generate_bar_graph($data, $ORDER_BY_VALUES);
+ print $graph;
+}
+
+#-------------------------------------------------------------------------------
+sub generate_bar_graph
+#-------------------------------------------------------------------------------
+{
+ my ($data, $by_values) = @_;
+
+ my @keys = keys %$data;
+
+ if ($by_values) # Order by values
+ {
+ @keys = sort
+ {
+ $data->{$b} <=> $data->{$a} # Descending
+ ||
+ $a cmp $b # Lexicographical
+
+ } @keys;
+ }
+ else # Order by labels
+ {
+ @keys = sort @keys; # Lexicographical only
+ }
+
+ my $width = max map { length } @keys;
+ my $graph = '';
+
+ for my $key (@keys)
+ {
+ my $bar = $BAR_CHARACTER x ($BAR_MULTIPLIER * $data->{$key});
+ $graph .= sprintf " %*s | %s\n", $width, $key, $bar;
+ }
+
+ return $graph;
+}
+
+################################################################################
diff --git a/challenge-032/athanasius/perl6/ch-1.p6 b/challenge-032/athanasius/perl6/ch-1.p6
new file mode 100644
index 0000000000..61c8f80eec
--- /dev/null
+++ b/challenge-032/athanasius/perl6/ch-1.p6
@@ -0,0 +1,123 @@
+use v6;
+
+################################################################################
+=begin comment
+
+Perl Weekly Challenge 032
+=========================
+
+Task #1
+-------
+Contributed by Neil Bowers
+
+Count instances
+
+Create a script that either reads standard input or one or more files specified
+on the command-line. Count the number of times and then print a summary, sorted
+by the count of each entry.
+
+So with the following input in file example.txt
+
+ apple
+ banana
+ apple
+ cherry
+ cherry
+ apple
+
+the script would display something like:
+
+ apple 3
+ cherry 2
+ banana 1
+
+For extra credit, add a -csv option to your script, which would generate:
+
+ apple,3
+ cherry,2
+ banana,1
+
+=end comment
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2019 PerlMonk Athanasius #
+#--------------------------------------#
+
+# Assumption: Data is to be treated as case-sensitive
+
+BEGIN say '';
+
+#===============================================================================
+sub MAIN
+(
+ **@args, #= File name(s) OR data word(s) OR none (to read
+ #= from stdin)
+ Bool:D :$csv = False, #= Generate output in CSV format
+ Bool:D :$help = False, #= Print usage details and exit
+)
+#===============================================================================
+{
+ if $help
+ {
+ $*USAGE.say;
+ }
+ else
+ {
+ my Str @strs = @args;
+ my Str @data = read-data(@strs);
+
+ # Count the entries
+
+ my UInt %count;
+ ++%count{$_} for @data;
+
+ # Sort keys by count: highest count first, equal counts in lexicographi-
+ # cal order. Adapted from:
+ # https://perldoc.perl.org/5.30.0/perlfaq4.html#How-do-I-sort-a-hash-
+ # (optionally-by-value-instead-of-key)%3f
+
+ my Str @keys = %count.keys.sort:
+ {
+ %count{$^b} <=> %count{$^a} # Descending
+ ||
+ $^a cmp $^b # Lexicographical
+ };
+
+ my Str $delimiter = $csv ?? ',' !! "\t";
+
+ "%s%s%d\n".printf: $_, $delimiter, %count{$_} for @keys;
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub read-data(Str:D @args --> Array[Str])
+#-------------------------------------------------------------------------------
+{
+ my Str @data;
+
+ if @args.elems > 0
+ {
+ for @args -> Str $arg
+ {
+ if $arg.IO.e
+ {
+ @data.push: $_ for $arg.IO.slurp.words;
+ }
+ else
+ {
+ @data.push: $arg;
+ }
+ }
+ }
+ else # Read data from standard input
+ {
+ "Enter data (^%s to stop):\n".printf: $*KERNEL eq 'win32' ?? 'Z' !! 'D';
+
+ @data = $*IN.words;
+ }
+
+ return @data;
+}
+
+################################################################################
diff --git a/challenge-032/athanasius/perl6/ch-2.p6 b/challenge-032/athanasius/perl6/ch-2.p6
new file mode 100644
index 0000000000..a6b756cfb6
--- /dev/null
+++ b/challenge-032/athanasius/perl6/ch-2.p6
@@ -0,0 +1,101 @@
+use v6;
+
+################################################################################
+=begin comment
+
+Perl Weekly Challenge 032
+=========================
+
+Task #2
+-------
+Contributed by Neil Bowers
+
+ASCII bar chart
+
+Write a function that takes a hashref where the keys are labels and the values
+are integer or floating point values. Generate a bar graph of the data and dis-
+play it to stdout.
+
+The input could be something like:
+
+ $data = { apple => 3, cherry => 2, banana => 1 };
+ generate_bar_graph($data);
+
+And would then generate something like this:
+
+ apple | ############
+ cherry | ########
+ banana | ####
+
+If you fancy then please try this as well: (a) the function could let you speci-
+fy whether the chart should be ordered by (1) the labels, or (2) the values.
+
+=end comment
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2019 PerlMonk Athanasius #
+#--------------------------------------#
+
+my Str constant $BAR-CHARACTER = '#';
+my UInt constant $BAR-MULTIPLIER = 4;
+my Bool constant $ORDER-BY-LABELS = False;
+my Bool constant $ORDER-BY-VALUES = True;
+
+BEGIN say '';
+
+#===============================================================================
+sub MAIN()
+#===============================================================================
+{
+ my Real %data = cherry => 2,
+ apple => 1.5,
+ banana => 3,
+ watermelon => 2,
+ mango => 3.8;
+
+ my Str $graph = generate-bar-graph(%data, $ORDER-BY-LABELS);
+ $graph.say;
+
+ $graph = generate-bar-graph(%data, $ORDER-BY-VALUES);
+ $graph.print;
+}
+
+#-------------------------------------------------------------------------------
+sub generate-bar-graph
+(
+ Real:D %data,
+ Bool:D $by-values = False,
+--> Str:D
+)
+#-------------------------------------------------------------------------------
+{
+ my Str @keys = %data.keys;
+
+ if $by-values # Order by values
+ {
+ @keys = @keys.sort:
+ {
+ %data{$^b} <=> %data{$^a} # Descending
+ || # then
+ $^a cmp $^b # Lexicographical
+ };
+ }
+ else # Order by labels
+ {
+ @keys = @keys.sort; # Lexicographical only
+ }
+
+ my UInt $width = @keys.map( { .chars } ).max;
+ my Str $graph = '';
+
+ for @keys -> Str $key
+ {
+ my Str $bar = $BAR-CHARACTER x ($BAR-MULTIPLIER * %data{$key});
+ $graph ~= " %*s | %s\n".sprintf: $width, $key, $bar;
+ }
+
+ return $graph;
+}
+
+################################################################################