# Perl Weekly Challenge 122.

My solutions (task 1 and task 2) to the The Weekly Challenge - 122.

# Task 1: Average of Stream

``````Submitted by: Mohammad S Anwar
You are given a stream of numbers, @N.

Write a script to print the average of the stream at every point.

Example
Input: @N = (10, 20, 30, 40, 50, 60, 70, 80, 90, ...)
Output:      10, 15, 20, 25, 30, 35, 40, 45, 50, ...

Average of first number is 10.
Average of first 2 numbers (10+20)/2 = 15
Average of first 3 numbers (10+20+30)/3 = 20
Average of first 4 numbers (10+20+30+40)/4 = 25 and so on.
``````

By keeping the current total and the number of data items the problem becomes a one-liner. I take input from STDIN, assuming that in a real application the data might not be known before the program is launched, so I can pipe in the data.

``````perl -E '\$i=1; say 10 * \$i++ while \$i<10;' | # data source \
perl -E 'while(<>){chomp; say "Input: ", \$_, " Output:", (\$T+=\$_)/(++\$N);}' # running average
``````

Results:

``````Input: 10 Output:10
Input: 20 Output:15
Input: 30 Output:20
Input: 40 Output:25
Input: 50 Output:30
Input: 60 Output:35
Input: 70 Output:40
Input: 80 Output:45
Input: 90 Output:50
``````

The full program would be:

``````# Perl weekly challenge 122
# Task 1: Average of stream
#
use strict;
use warnings;
use v5.12;
my \$counter=0; # item counter
my \$total=0; # running total
while(<>){
chomp;
++\$counter;
\$total += \$_;
my \$average=\$total/\$counter;
say "Input: \$_ Output: \$average";
}
``````

Example:

``````perl -E '\$i=1; say 10 * \$i++ while \$i<10;' | ./ch-1.pl
``````

Results:

``````Input: 10 Output: 10
Input: 20 Output: 15
Input: 30 Output: 20
Input: 40 Output: 25
Input: 50 Output: 30
Input: 60 Output: 35
Input: 70 Output: 40
Input: 80 Output: 45
Input: 90 Output: 50
``````

Other examples

1. Average of triangular numbers

``````perl -E '\$i=1; say \$i++ while \$i<10;' |./ch-1.pl
``````

Results:

``````Input: 1 Output: 1
Input: 2 Output: 1.5
Input: 3 Output: 2
Input: 4 Output: 2.5
Input: 5 Output: 3
Input: 6 Output: 3.5
Input: 7 Output: 4
Input: 8 Output: 4.5
Input: 9 Output: 5
``````
2. Average of first squares:

``````perl -E '\$i=1; say +(\$i++)**2 while \$i<10;' |./ch-1.pl
``````

Results:

``````Input: 1 Output: 1
Input: 4 Output: 2.5
Input: 9 Output: 4.66666666666667
Input: 16 Output: 7.5
Input: 25 Output: 11
Input: 36 Output: 15.1666666666667
Input: 49 Output: 20
Input: 64 Output: 25.5
Input: 81 Output: 31.6666666666667
``````
3. Average of first cubes:

``````perl -E '\$i=1; say +(\$i++)**3 while \$i<10;' |./ch-1.pl
``````

Results:

``````Input: 1 Output: 1
Input: 8 Output: 4.5
Input: 27 Output: 12
Input: 64 Output: 25
Input: 125 Output: 45
Input: 216 Output: 73.5
Input: 343 Output: 112
Input: 512 Output: 162
Input: 729 Output: 225
``````

``````Submitted by: Mohammad S Anwar
You are given a score \$S.

You can win basketball points e.g. 1 point, 2 points and 3
points.

Write a script to find out the different ways you can score
\$S.

Example
Input: \$S = 4
Output: 1 1 1 1
1 1 2
1 2 1
1 3
2 1 1
2 2
3 1

Input: \$S = 5
Output: 1 1 1 1 1
1 1 1 2
1 1 2 1
1 1 3
1 2 1 1
1 2 2
1 3 1
2 1 1 1
2 1 2
2 2 1
2 3
3 1 1
3 2
``````

I solve the problem recursively. The possible sets of points for a given score S are those for a lower score `S-1`, `S-2` or `S-3` followed by a single, double or triple point. I just have to be careful with the initial conditions, either a single, a double or a triple score.

``````# Perl weekly challenge 122
use strict;
use warnings;
use v5.12;
use Memoize;
memoize("points");

foreach (@ARGV){
say "Input: \$_\nOutput:\n\t", join "\n\t", map {join " ", @\$_} points(\$_);
}
sub points{
my \$s=shift;
return ()  if \$s<=0;
# Append a 1, 2 or 3 point throw to the previous points
my @result=((map {my @x=@\$_;push @x,1; [@x]}points(\$s-1)),
(map {my @x=@\$_;push @x,2; [@x]}points(\$s-2)),
(map {my @x=@\$_;push @x,3; [@x]}points(\$s-3)));
push @result, [\$s] if \$s<=3;
return @result;
}
``````

Examples:

``````./ch-2.pl 4 5
``````

Results:

``````Input: 4
Output:
1 1 1 1
2 1 1
1 2 1
3 1
1 1 2
2 2
1 3
Input: 5
Output:
1 1 1 1 1
2 1 1 1
1 2 1 1
3 1 1
1 1 2 1
2 2 1
1 3 1
1 1 1 2
2 1 2
1 2 2
3 2
1 1 3
2 3
``````

Memoization makes a difference for large scores. For example, for `S=24` it took about 5 times longer to obtain the result without memoization compared with the result with memoization. However, memoization can produce surprises. For example, a line such as

``````@result=((map {push @\$_,1; \$_}points(\$s-1),...);
``````

(which I wrote in my first attempt) would work without memoization but it fails with memoization, as the variable `\$_` from previous results would be inadvertently modified. Thus, the need for the temporal variable `@x`.

Larger example:

``````time (./ch-2.pl 25 | wc) 2>&1
``````

Results:

``````2555759 40058424 82672617

real	0m15.589s
user	0m13.761s
sys	0m1.867s
``````

which means the program found `2555759-2=2555757` different sets of points for a total score of 25 in 15s in my laptop.

Written on July 19, 2021