Perl Weekly Challenge: Week 238
Challenge 1:
Running Sum
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)
Hooray we can do a one-liner again this week!
$t
stores the running total. It is initially 0. .map()
is used to iterate through the command line arguments adding each
to the current value of $t
. And that's it. The result is a transformed array where each element is the total of itself and
all the elements preceding it. The rest of the code is just for outputting the results in a pretty way.
my $t=0;say q{(},@*ARGS.map({$t+=$_}).join(q{, }),q{)}
The Perl version is even shorter because, unlike in Raku, we don't need to initialize $t
.
say q{(},(join q{, },map{$t+=$_}@ARGV),q{)}
Challenge 2:
Persistence Sort
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)
To solve this problem in Raku we start by creating a hash that will map the integers provided to the number of steps it takes to reduce them to single-digit numbers.
my %steps;
Then for each integer...
for @ints -> $int {
...first we have to copy it into another variable $n
because $int
is immutable.
my $n = $int;
We use a variable $s
to count the number of steps taken. It is initially set to 0.
my $s = 0;
Then while $n
has more than one digit...
while $n.chars > 1 {
...we split it into individual digits with .comb()
and multiply all these digits together with [*]
.
The result becomes the new value of $n
.
$n = [*] ($n.comb);
And we increment the number of steps taken.
$s++;
}
Once we are down to a single digit, the original integer and the numbers of steps are added to
the %steps
hash. $n
is thrown away; we won't need it.
%steps{$int} = $s;
}
Once we have the step count for all the integers, we can sort them into a new array in ascending numerical order by number of steps. When there is a tie, as the spec suggests, we place the smaller integer first.
my @sorted = %steps.keys.sort({ %steps{$^a} <=> %steps{$^b} || $^a > $^b });
And then we nicely format the results and print them.
say q{(}, @sorted.join(q{, }), q{)};
The Perl version only has one big difference.
my %steps;
for my $int (@ints) {
my $n = $int;
my $s = 0;
while (length $n > 1) {
Because we don't have the handy [*]
operator, we have to split $n
into digits and
loop through them multiplying them as we go.
my $t = 1;
my @digits = split //, $n;
for my $digit (@digits) {
$t *= $digit;
}
The rest is the same.
$n = $t;
$s++;
}
$steps{$int} = $s;
}
my @sorted = sort { $steps{$a} <=> $steps{$b} || $a > $b } keys %steps;
say q{(}, (join q{, }, @sorted), q{)};