Perl Weekly Challenge 238.

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

Task 1: Running Sum

Submitted by: Mohammad S Anwar
You are given an array of integers.

Write a script to return the running sum of the given array.
The running sum can be calculated as sum[i] = num[0] + num[1] + …. + num[i].

Example 1
Input: @int = (1, 2, 3, 4, 5)
Output: (1, 3, 6, 10, 15)
Example 2
Input: @int = (1, 1, 1, 1, 1)
Output: (1, 2, 3, 4, 5)
Example 3
Input: @int = (0, -1, 1, 2)
Output: (0, -1, 0, 2)

List::Util provides the function reductions which produces the partial reductions of a list by an arbitrary binary operation, not only the final reduction over the whole list. In this case, we are asked for the running reduction using the sum. This leads to a very simple one-liner.

Example 1:

perl -MList::Util=reductions -E '
say "@ARGV -> ", join " ", reductions {$a+$b} @ARGV
' 1 2 3 4 5

Results:

1 2 3 4 5 -> 1 3 6 10 15

Example 2:

perl -MList::Util=reductions -E '
say "@ARGV -> ", join " ", reductions {$a+$b} @ARGV
' 1 1 1 1 1

Results:

1 1 1 1 1 -> 1 2 3 4 5

Example 3:

perl -MList::Util=reductions -E '
say "@ARGV -> ", join " ", reductions {$a+$b} @ARGV
' 0 -1 1 2

Results:

0 -1 1 2 -> 0 -1 0 2

The full code is almost identical.

 1  # Perl weekly challenge 238
 2  # Task 1:  Running Sum
 3  #
 4  # See https://wlmb.github.io/2023/10/09/PWC238/#task-1-running-sum
 5  use v5.36;
 6  use List::Util qw(reductions);
 7  die <<~"FIN" unless @ARGV;
 8      Usage: $0 N1 [N2...]
 9      to return the running sum N1, N1+N2, N1+N2+N3...
10      of the numbers N1, N2...
11      FIN
12  say "@ARGV -> ", join " ", reductions {$a+$b} @ARGV

Examples:

./ch-1.pl 1 2 3 4 5
./ch-1.pl 1 1 1 1 1
./ch-1.pl 0 -1 1 2

Results:

1 2 3 4 5 -> 1 3 6 10 15
1 1 1 1 1 -> 1 2 3 4 5
0 -1 1 2 -> 0 -1 0 2

Task 2: Persistence Sort

Submitted by: Mohammad S Anwar
You are given an array of positive integers.

Write a script to sort the given array in increasing order with
respect to the count of steps required to obtain a single-digit
number by multiplying its digits recursively for each array element.
If any two numbers have the same count of steps, then print the
smaller number first.

Example 1
Input: @int = (15, 99, 1, 34)
Output: (1, 15, 34, 99)

15 => 1 x 5 => 5 (1 step)
99 => 9 x 9 => 81 => 8 x 1 => 8 (2 steps)
1  => 0 step
34 => 3 x 4 => 12 => 1 x 2 => 2 (2 steps)
Example 2
Input: @int = (50, 25, 33, 22)
Output: (22, 33, 50, 25)

50 => 5 x 0 => 0 (1 step)
25 => 2 x 5 => 10 => 1 x 0 => 0 (2 steps)
33 => 3 x 3 => 6 (1 step)
22 => 2 x 2 => 4 (1 step)

I make a function to evaluate the number of steps to get one digit using split and product repeatedly and use it as a first test in a sort. The solution fits a simple two-liner.

Example 1:

perl -MList::Util=product -E '
sub f($x){$r=0;++$r,$x=product split "", $x while($x>=10); $r}
say "@ARGV -> ", join " ", sort {f($a)<=>f($b)||$a<=>$b} @ARGV
' 15 99 1 34

Results:

15 99 1 34 -> 1 15 34 99

Example 2:

perl -MList::Util=product -E '
sub f($x){$r=0;++$r,$x=product split "", $x while($x>=10); $r}
say "@ARGV -> ", join " ", sort {f($a)<=>f($b)||$a<=>$b} @ARGV
' 50 25 33 22

Results:

50 25 33 22 -> 22 33 50 25

It is interesting to note that the process of reducing a number by multiplying its digits always converges, as the product of the decimal digits of an integer is always smaller than the number itself.

The full code is almost identical, except for a few checks.

 1  # Perl weekly challenge 238
 2  # Task 2:  Persistence Sort
 3  #
 4  # See https://wlmb.github.io/2023/10/09/PWC238/#task-2-persistence-sort
 5  use v5.36;
 6  use List::Util qw(product all);
 7  use POSIX qw(floor);
 8  sub steps($x){
 9      my $result=0;
10      ++$result , $x=product split "", $x
11  	while($x>=10);
12      $result
13  }
14  die <<~"FIN" unless @ARGV;
15      Usage: $0 N1 [N2...]
16      to sort the list N1 N2 according to the number of steps required
17      to bring the number to one digit and then according to value
18      FIN
19  die "Only natural numbers allowed" unless all {0<=floor($_)&&floor($_)==$_} @ARGV;
20  say "@ARGV -> ", join " ",
21      sort {steps($a)<=>steps($b)||$a<=>$b} @ARGV

Examples:

./ch-2.pl 15 99 1 34
./ch-2.pl 50 25 33 22

Results:

15 99 1 34 -> 1 15 34 99
50 25 33 22 -> 22 33 50 25

/;

Written on October 9, 2023