Kian-Meng Ang Weekly Review: Challenge - 030

Sunday, Oct 27, 2019| Tags: Perl

Continues from previous week.

Feel free to submit a merge request or open a ticket if you found any issues with this post. We highly appreciate and welcome your feedback.

For a quick overview, go through the original tasks and recap of the weekly challenge.

Task #1

CPAN modules used: Const::Fast, Date::Christmas, Date::Manip::Date, Date::Simple, DateTime, DateTime::Format::HTTP, Modern::Perl, POSIX, Test::More, Time::Local, Time::Piece, Time::Seconds, constant, feature, strict, utf8, warnings

This task was a good example that some people say they can find almost everything in CPAN to solve a computing problem. We didn’t even realize that until we read the solution by Markus Holzer which used a CPAN module, Date::Christmas that calculates the Christmas day of the week. His answer was a good start for anyone to have a quick overview on the general approach of solving this task. Basically loop through the year from 2019 till 2100 and determine whether the day of 25th of December is Sunday either through CPAN modules or manual calculation.

The next solution you should look into was submitted by Colin Crain which implemented three different algorithms to calculate the day of the month.

For other submissions which implemented these algorithms, look into those solutions which took the purist approach without using any CPAN modules. These people includes Adam Russell, Trenton Langer, Vyacheslav Volgarev, Jaldhar H. Vyas, Leoltron, Colin Crain and Creewick.

Task #2

CPAN modules used: Algorithm::Combinatorics, Const::Fast, Data::Dumper, List::Util, Math::Combinatorics, Modern::Perl, PDL, POSIX, Set::Product, Test::More, Time::Piece, boolean, constant, feature, strict, utf8, warnings

Start with the solution by TesterR59. Simple and straightforward brute-force approach with duplicated permutations. Again, Colin Crain showed us how to generate different series based on the assumptions made.

While there were different ways to remove the duplication, the solution by Andrezgz was the best explained so far. We simply grok it by first read. This was a good example to illustrate that well-written comments improve understanding of the code.

my %groups;

# duplicates are allowed on the same group
# 0 is ommited in all loops (it's not positive)
for my $first ( 1..10 ) {
  for my $second ( 1..10 ) {
      my $third =  12 - $first - $second;   # the sum is 12 (an even number) so one of them is even
      next if $third <= 0;                  # none of them is negative
      my $key = join ' ',                   # create a unique combination ...
                sort { $a <=> $b }          # by sorting ...
                $first, $second, $third;    # the 3 numbers.
      print $key.$/ unless $groups{$key}++; # print combination only once.

Is there anyone else who code in such way? Yes, Joelle Maslak. Besides the mathematical background on the problem and assumptions made. The solution also demonstrated different Perl 5 idioms, for example, generating and transforming a list, as shown below. Be sure to check out the remaining part of the solution to pick up a trick or two.

# Read this next portion of code from bottom up.
say join "\n",    # Build a string, seperating sets by newlines
    map { join( ",", $_->@* ) }    # Make the sets into comma-deliminated strings
    grep { sum( $_->@* ) == 12 }   # Make sure these numbers sum to 12
    grep { $_->[1] < $_->[2] }     # Make sure last number is the biggest
    grep { $_->[0] < $_->[1] }     # Make sure 2nd number is bigger than 1st
    cross( [ 1 .. 7 ], [ 2 .. 8 ], [ 3 .. 9 ] );    # Create a list where each element is a list
                                                    # of 3 numbers.

For generating permutations and combinations, the solution by Adam Russell have shown us that this was doable through theMath::Combinatorics CPAN module. Markus Holzer also did the same with the Algorithm::Combinatorics CPAN module as shown below. Compare and contrast his solution against Joelle to find opposite approach to solve this task.

  use Modern::Perl;
  use List::Util qw( sum );
  use Set::Product qw( product );
  use Algorithm::Combinatorics qw( variations_with_repetition );

  product {
      my ( $even, $rest ) = @_;

      say join( ", ", $even, @$rest )
          if sum( $even, @$rest ) == 12;
  [ 2, 4 .. 10 ],
  [ variations_with_repetition( [1 .. 10], 2 ) ];

And we thought we’ve seen it all, yet, Yet Ebreo reminded us that Perl is a write-only language where you can cramp everything into a one-liner.

my $r = join ",", 0..12;
eval==12  && say y/+/,/r while glob "{$r}+{$r}+{$r}";

From the examples we’ve reviewed so far, we’ve observed that in Perl, there’s more than one way to do it (TMTOWTDI). So, which is your preferred style? Send your feedback to the Perl Weekly Challenge (PWC) Twitter account.


(1) Christmas Twelfth Cometh Perl 6 by Arne Sommer

(2) Perl Weekly Challenge 030 by Adam Russell

(3) Blogging Challenge 30 by Dave Jacoby

(4) Perl Weekly Challenge 30: Sunday Christmas and Triplets by Laurent Rosenfeld

(5) Perl Weekly Challenge: Week 30 by Jaldhar H. Vyas

(6) RogerBW’s Blog: Perl Weekly Challenge 30 by Roger Bell_West

(7) Perl Weekly Challenge 030: Sunday Christmas and Series with sum 12 by E. Choroba


If you have any suggestions or ideas then please do share with us.

Contact with me