I’ve been doing the Weekly
Challenges. The
latest
involved various list processing. (Note that this ends today.)
Task 1: Maximum Count
You are given an array of integers.
Write a script to return the maximum between the number of positive
and negative integers. Zero is neither positive nor negative.
One could do this with a functional approach: filter for positive and
count, filter for negative and count, return the larger value. But my
native idiom is to do multiple things in the same loop rather than set
up multiple loops, and that's what I did here. For example in
PostScript (where neg
is a reserved word I don't want to overwrite,
and there's no direct "else if" construct):
/maximumcount {
0 dict begin
/pos 0 def
/ng 0 def
{
/n exch def
Is the value positive?
n 0 gt {
/pos pos 1 add def
} {
Otherwise, is it negative?
n 0 lt {
/ng ng 1 add def
} if
} ifelse
} forall
pos ng max
end
} bind def
(maximumcount) test.start
[-3 -2 -1 1 2 3] maximumcount 3 eq test
[-2 -1 0 0 1] maximumcount 2 eq test
[1 2 3 4] maximumcount 4 eq test
test.end
More conventionally in Typst:
#let maximumcount(a) = {
let pos = 0
let neg = 0
for n in a {
if n > 0 {
pos += 1
} else if n < 0 {
neg += 1
}
}
calc.max(pos, neg)
}
Task 2: Sum Difference
You are given an array of positive integers.
Write a script to return the absolute difference between digit sum
and element sum of the given array.
Some optimisations are possible here.
-
We only care about the difference in sums. So for any value we only
need the difference between digit sum and full value, and then we
can add them all to get the answer.
-
If an element is less than 10, its value equals its the digit sum,
so the contribution to the difference is zero and it can be
skipped.
-
Consider a two-digit number XY
. The contribution to the element
sum X×10+Y
can never be less than the contribution to the digit
sum X+Y
. So I don't need to bother with an abs
function or
using integer types that can become negative, as long as I set
things up with mild care.
In Raku:
sub sumdifference(@a) {
my $delta = 0;
for @a -> $x {
Is it worth considering this element at all?
if ($x >= 10) {
If so, calculate the sum of digits.
my $digitsum = 0;
my $xa = $x;
while ($xa > 0) {
$digitsum += $xa % 10;
$xa = floor($xa / 10);
}
Add the difference between value and digit sum.
$delta += $x - $digitsum;
}
}
$delta;
}
If this were performance-critical I might discard the ones digit
before doing the calculation, but it would take profiling to determine
whether that would be usefully faster.
Full code on
github.