Perl Weekly Challenge W023 - Difference, Factors and Poem

This week's challenge is composed of three tasks.The first one is to get the n-th order of forward difference of a given list.

Task #1 - N-th order difference:

Suppose we have list (X) of numbers: 5, 9, 2, 8, 1, 6 and we would like to create 1st order forward difference series (Y). So using the formula Y(i) = X(i+1) - X(i), we get the following numbers: (9-5), (2-9), (8-2), (1-8), (6-1). In short, the final series would be: 4, -7, 6, -7, 5. If you noticed, it has one less number than the original series. Similary you can carry on 2nd order forward difference series like: (-7-4), (6+7), (-7-6), (5+7) => -11, 13, -13, 12.

Solution:
use strict;
use warnings;
use 5.010;

my ($n, @list) = @ARGV;

die "Usage: ch-1.pl  \n\tn must be less than the number of elements in list\n\tlist values are space separated\n" if !@ARGV;
die "n($n) must be less than the number(".@list.") of elements in list\n" if $n>= @list;


(@list = map $list[$_]-$list[$_-1],1..$#list) for 1..$n;

say "@list";

My solution is pretty straight-forward. It shows the usage when no arguments are passed. And also checks if the value of N is greater than or equal to number of elements in list, an invalid case.

It iterates through the @list using map from index 1 to last index, the difference of the current element and previous is then returned for each iteration. The resulting list is saved in @list and the process is repeated N times. The final value of @list is then printed

Task #2 - Prime Factorization:
Next task is prime factorization. In this task, I've implemented three different methods:

  • Using system command factor
  • Using factor in ntheory module
  • Using trial division and modulo
Create a script that prints Prime Decomposition of a given number. The prime decomposition of a number is defined as a list of prime numbers which when all multiplied together, are equal to that number. For example, the Prime decomposition of 228 is 2,2,3,19 as 228 = 2 * 2 * 3 * 19.

Solution: Backticks and factor
my $n   = $ARGV[0];
#Backticks solution using factor, works both on windows and linux :D
say "Using backticks and factor system command:";
say `factor $n`=~s/.+: //r;

The command factor prints out the factors of the specified number which basically accomplishes the task at hand. The substitution in the code is to remove the input number+colon in the output. I've been using this method in code golfing where prime factorization is needed.

Solution: Module ntheory factor
use ntheory 'factor';
my $n   = $ARGV[0];
@r = factor $n;
say "@r\n";
The ntheory module written by Dana Jacobsen has its own factor command. It is fast and can easily handle large numbers.

Solution: Trial division and modulo
use bigint;
my @r;
my $n   = $ARGV[0];
@r = ();
while ($n % 2<1) {
    push @r, 2;
    $n /= 2;
}
my $f = 3;
while ($f*$f<=$n) {
    while ($n % $f<1) {
        push @r, $f;
        $n /= $f;
    }
    $f+=2;
}
$n>1 && push @r, $n;
say "@r\n";
The code divides the number by two while it is divisible by two, 2 is pushed to array @r in each iteration. This is done so that we can proceed to the next prime which is three and then do an increment of +2 to check only the odd numbers instead of doing +1 increments.

This method is the slowest compared to the first two. The performance is greatly affected by the number of factors. A large number with lesser prime factors tends to be slower.


Task #3 - Random Poem:
This is my first attempt in doing API. There is a "little push" (being the easiest) in the task description for me to take on the challenge. So thanks, @Mohammad S Anwar!

Write a script to use Random Poems API. This is the easiest API, I have come across so far. You don’t need API key for this. They have only route to work with (GET). The API task is optional but we would love to see your solution.

Solution:
use strict;
use warnings;
use 5.010;

use LWP::Simple qw(get);
use JSON;
binmode STDOUT, ":encoding(UTF-8)";

my $api_content = get "https://www.poemist.com/api/v1/randompoems";
my @data = @{ JSON->new->utf8->decode($api_content) };

#Printing the info of the first poem
say "$data[0]{title} - $data[0]{poet}{name} - $data[0]{url}\n";

#Printing the content of the first poem
say "$data[0]{content}";

In this task, I used the get command from LWP module. The API returns a string in JSON format so I used JSON module to decode and save the structure in an array @data

The API returns 5 random poems in each call which can be accessed using indices from 0 to 4. Information in @data can be retrieved as follows:
$data[index]{title|content|poet}{name}

Leave a comment

About Yet Ebreo

user-pic I blog about Perl.