Perl Weekly Challenge: Week 163
Challenge 1:
Sum Bitwise Operators
You are given a list of positive numbers,
@n
.Write script to calculate the sum of bitwise & operator for all unique pairs.
Example 1:
Input: @n = (1, 2, 3)
Output: 3
Since (1 & 2) + (2 & 3) + (1 & 3) => 0 + 2 + 1 => 3.
Example 2:
Input: @n = (2, 3, 4)
Output: 2
Since (2 & 3) + (2 & 4) + (3 & 4) => 2 + 0 + 0 => 2.
In Raku we can solve this with a one-liner.
@*ARGS.combinations(2).map({ [+&] $_ }).sum.say;
@*ARGS
are the arguments passed on the command line. These should be a list of positive numbers though I'm not actually checking that. We apply .combinations(2)
to them to get unique pairs. Then .map()
is used to apply bitwise and to each pair. (bitwise and is +&
in Raku not just &
which always trips me up.) I could have expressed this as $_[0] +& $_[1]
but decided to use the hyperoperator [+&]
instead. It just reads better IMO. At this point, we have a list of results of each and operation. These are totalled with .sum()
. I could have used [+]
but this allows me to continue chaining
In Perl, we have to be a bit more verbose as we are missing .sum()
and .combinations()
but I already had replacement functions for them and armed with those, the core part of the Perl solution is also one line.
say sum([map { $_->[0] & $_->[1] } combinations(\@ARGV, 2) ]);
Challenge 2:
Summations
You are given a list of positive numbers,
@n
.Write a script to find out the summations as described below.
Example 1:
Input: @n = (1, 2, 3, 4, 5)
Output: 42
1 2 3 4 5
2 5 9 14
5 14 28
14 42
42
The nth Row starts with the second element of the (n-1)th row.
The following element is sum of all elements except first element of previous row.
You stop once you have just one element in the row.
Example 2:
Input: @n = (1, 3, 5, 7, 9)
Output: 70
1 3 5 7 9
3 8 15 24
8 23 47
23 70
70
This one took me a little while to understand but ultimately proved to be quite straightforward to solve. According to the spec, the nth row begins with the (n-1)th element of the previous row. So we start the script with
all the elements of the input except the first. I've called this new array @previous
but in hindsight @current
would have been more appropriate.
my @previous = @n[1 .. *];
There is also a variable to store the running total.
my $total;
Now as long as there is atleast one element left in @previous
...
while @previous.elems {
We initalize $total
to the value of the first element.
$total = @previous[0];
And set up an array to hold the next line. It is initialized with $total
.
my @next = ( $total );
Then for each of the remaining elements in @previous
, we add its value to $total
and
add the new value of $total
to @next
.
for 1 ..^ @previous.elems -> $i {
$total += @previous[$i];
@next.push($total);
}
Finally, we make the new value of @previous
equal to all the elements of @next
except the
first one.
@previous = @next[1 .. *];
}
After this loop finishes, $total
contains the final answer so we print it.
say $total;
For once, Perl has everything we need to translate the Raku code above. The syntax isn't even particularly ungainly compared to the Raku version.
my @previous = @n[1 .. $#n];
my $total;
while (scalar @previous) {
$total = $previous[0];
my @next = ( $total );
for my $i (1 .. scalar @previous - 1) {
$total += $previous[$i];
push @next, $total;
}
@previous = @next[1 .. $#next];
}
say $total;