PERL WEEKLY CHALLENGE – 033

This is my third week participating into the weekly challenge.

Again apologies for not having the syntax highlighter on some of the solutions as the > symbols become & gt; and ruins the solution.


Easy Challenge

“Count Letters (A..Z)
Create a script that accepts one or more files specified on the command-line and count the number of times letters appeared in the files.”

Example files

The quick brown fox jumps over the lazy dog.
καλησπέρα

I used getc to grab the character from the file handle and store the character count in a hash. I used the \w (word character) for regex matching to make sure we grabbed some of the UTF-8 chars.

Then format print the letter and the count.

Perl 5 solution

#!/usr/bin/perl
# Test: ./ch1.pl example1.txt example2.txt
use strict;
use warnings;
binmode STDOUT, ':utf8';
my %counts;

# Loop through each file
for my $file (@ARGV) {
	open my $fh, "<:encoding(UTF-8)", $file or die "$file: $! \n";

	# Increment count for each word char
	while (my $char = getc($fh)) {
		$counts{lc($char)}++ if (lc($char) =~ /[\w]/);
	}
}

# Print each char and count
for my $char (sort keys %counts) {
	printf("%2s %5i\n", $char, $counts{$char});
}

Output

 a     1
 b     1
 c     1
 d     1
 e     3
 f     1
 g     1
 h     2
 i     1
 j     1
 k     1
 l     1
 m     1
 n     1
 o     4
 p     1
 q     1
 r     2
 s     1
 t     2
 u     2
 v     1
 w     1
 x     1
 y     1
 z     1
 έ     1
 α     2
 η     1
 κ     1
 λ     1
 π     1
 ρ     1
 σ     1

Raku solution

# Test: perl6 ch1.p6 example1.txt example2.txt
use v6.d;

sub MAIN (*@filenames) {
	my %counts;

	# Loop through each file
	for @filenames -> $filename {
		my $fh = $filename.IO.open orelse .die;

		# Increment count for each word char
		while (my $char = $fh.getc) {
			%counts{$char.lc}++ if ($char.lc ~~ /\w/);
		}
	}

	# Print each char and count
	for %counts.keys.sort -> $item {
		"%2s %5i\n".printf($item, %counts{$item});
	}
}

Output

 a     1
 b     1
 c     1
 d     1
 e     3
 f     1
 g     1
 h     2
 i     1
 j     1
 k     1
 l     1
 m     1
 n     1
 o     4
 p     1
 q     1
 r     2
 s     1
 t     2
 u     2
 v     1
 w     1
 x     1
 y     1
 z     1
 έ     1
 α     2
 η     1
 κ     1
 λ     1
 π     1
 ρ     1
 σ     1

Hard Challenge

Formatted Multiplication Table
Write a script to print 11×11 multiplication table, only the top half triangle.”

I had a lot of fun doing this one, something quite satisfying about ascii tables. So just using prinft to format the table nicely and some for loops to populate it.

For my raku solution i decided to play around with multi method. There are probably better ways of doing this, but I’m using the challenges to learn something new about raku every week.

Perl 5 solution

#!/usr/bin/perl
# Test: ./ch2.pl
use strict;
use warnings;

generate_x_table(11);

# Generates the multiplication table
sub generate_x_table {
	my $num = shift;

	for my $i (0..$num) {
		my $line = ($i == 0) ?
			_table_head($num) :
			_table_body($i, $num);
		print $line;
	}
}

# Returns the table head string
sub _table_head {
	my $num = shift;
	my $line = sprintf ("%4s|", 'x');

	for my $i (1..$num) {
		$line .= sprintf("%4i", $i);
	}

	return $line . "\n" . '----+' . '----' x $num . "\n";
}

# Returns the table row string for $i
sub _table_body {
	my ($current, $num) = @_;
	my $line = sprintf ("%4i|", $current);

	for my $i (1..$num) {
		$line .= ($current <= $i) ?
			sprintf("%4i", $i * $current) : ' ' x 4;
	}

	$line .= "\n";

	return $line;
}

Output

   x|   1   2   3   4   5   6   7   8   9  10  11
----+--------------------------------------------
   1|   1   2   3   4   5   6   7   8   9  10  11
   2|       4   6   8  10  12  14  16  18  20  22
   3|           9  12  15  18  21  24  27  30  33
   4|              16  20  24  28  32  36  40  44
   5|                  25  30  35  40  45  50  55
   6|                      36  42  48  54  60  66
   7|                          49  56  63  70  77
   8|                              64  72  80  88
   9|                                  81  90  99
  10|                                     100 110
  11|                                         121

Raku solution

# Test: perl6 ch2.p6
use v6.d;

sub MAIN () {
	generate-x-table(11);
}

# Generates the multiplication table
sub generate-x-table (Int $num) {
	table-content($_, $num).say for (0..$num);
}

# Returns the table head string
multi table-content(Int $current where { $current == 0}, Int $num) {
	my $line = "%4s|".sprintf("x");
	$line ~= "%4i".sprintf($_) for (1..$num);
	return $line ~ "\n" ~ '----+' ~ '----' x $num;
}

# Returns the table row string for $i
multi table-content(Int $current, Int $num) {
	my $line = "%4i|".sprintf($current);

	for (1..$num) -> $i {
		$line ~= ($current <= $i) ??
			"%4i".sprintf($i * $current) !! ' ' x 4;
	}

	return $line;
}

Output

   x|   1   2   3   4   5   6   7   8   9  10  11
----+--------------------------------------------
   1|   1   2   3   4   5   6   7   8   9  10  11
   2|       4   6   8  10  12  14  16  18  20  22
   3|           9  12  15  18  21  24  27  30  33
   4|              16  20  24  28  32  36  40  44
   5|                  25  30  35  40  45  50  55
   6|                      36  42  48  54  60  66
   7|                          49  56  63  70  77
   8|                              64  72  80  88
   9|                                  81  90  99
  10|                                     100 110
  11|                                         121

One thought on “PERL WEEKLY CHALLENGE – 033

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s