diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2019-11-03 15:28:08 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-11-03 15:28:08 +0000 |
| commit | db600416f294a2abed5c0687aaa88ac429fa828e (patch) | |
| tree | 4d4fa58efe7bb374ec59062951ba3275842cb786 | |
| parent | ae7d3579e987a745a828d2ef17ff125b5bb1b788 (diff) | |
| parent | f070d686a17e6cc6735dfd45e7b0c9a760851948 (diff) | |
| download | perlweeklychallenge-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.pl | 167 | ||||
| -rw-r--r-- | challenge-032/athanasius/perl5/ch-2.pl | 111 | ||||
| -rw-r--r-- | challenge-032/athanasius/perl6/ch-1.p6 | 123 | ||||
| -rw-r--r-- | challenge-032/athanasius/perl6/ch-2.p6 | 101 |
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; +} + +################################################################################ |
