Perl Weekly Challenge: Week 320

Challenge 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.

Example 1
Input: @ints = (-3, -2, -1, 1, 2, 3)
Output: 3

There are 3 positive integers.
There are 3 negative integers.
The maximum between 3 and 3 is 3.
Example 2
Input: @ints = (-2, -1, 0, 0, 1)
Output: 2

There are 1 positive integers.
There are 2 negative integers.
The maximum between 2 and 1 is 2.
Example 3
Input: @ints = (1, 2, 3, 4)
Output: 4

There are 4 positive integers.
There are 0 negative integers.
The maximum between 4 and 0 is 4.

This is another job for a Raku one-liner, well, if you stretch the meaning of one line a little bit. In fact my solution consists of two statements; for didactic purposes, I'll show them as two sperate lines. Just pretend they are one. :-)

Raku's List class has a poweful method called .classify() that takes elements and adds them to a Hash depending on the criteria we set. Here, if the element is negative, it gets added to the n key of %a. If it is positive, it will be added to the p key. If it is zero, it gets added to the z key which we will subsequently ignore.

@*ARGS.classify({ $_ < 0  ?? "n" !! $_ > 0 ?? "p" !! "z" }, :into(my %a));

Now we can count the number of elements in %a<p> and %a<n> with .elems(), find the maximum of the two with .max() and print the result with .say().

(%a<p>.elems, %a<n>.elems).max.say;

(Full code on Github.)

Perl doesn't have .classify() so we have to emulate it. However as we don't need all its' bells and whistles we can simplify a little bit.

Instead of a Hash we just define two variable to store the count of positive negatives.

my $neg = 0;
my $pos = 0;

That's another difference; as we iterate through the elements of @ints we increment counts rather than store the element itself as Raku did. Also we can ignore zeros.

for my $int (@ints) {
    if ($int < 0) {
        $neg++;
    }  elsif ($int > 0) {
        $pos++;
    }

}

We also need to provide our own imlementation of ,max().

say max($neg, $pos);

(Full code on Github.)

Challenge 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.

Example 1
Input: @ints = (1, 23, 4, 5)
Output: 18

Element sum: 1 + 23 + 4 + 5 => 33
Digit sum: 1 + 2 + 3 + 4 + 5 => 15
Absolute difference: | 33 - 15 | => 18
Example 2
Input: @ints = (1, 2, 3, 4, 5)
Output: 0

Element sum: 1 + 2 + 3 + 4 + 5 => 15
Digit sum: 1 + 2 + 3 + 4 + 5 => 15
Absolute difference: | 15 - 15 | => 0
Example 3
Input: @ints = (1, 2, 34)
Output: 27

Element sum: 1 + 2 + 34 => 37
Digit sum: 1 + 2 + 3 + 4 => 10
Absolute difference: | 37 - 10 | => 27

This one is also a Raku one-liner. We use the command-line arguments to provide input. Finding the element sum is dead simple; we just use the .sum() method. From this amount we have to subtract the digit sum which is slightly more complicated. We use .map() to iterate over the integers and run .comb() on each one to split it into individual digits. This will give us a List of Lists so we use .flat() to "flatten" them into one list. Finally .sum() is used again.

say @*ARGS.sum - @*ARGS.map({ $_.comb }).flat.sum

(Full code on Github.)

Unfortunately we can't make a one-liner in Perl because we need to provide our own implentation of .sum(). But the core of the script is one line. (And we don't have to deal with flattening arrays.)

say sum(@ints) - sum(map { split //, $_ } @ints);

(Full code on Github.)