Perl Weekly Challenge: Week 262
Challenge 1:
Max Positive Negative
You are given an array of integers,
@ints
.Write a script to return the maximum number of either positive or negative integers in the given array.
Example 1
Input: @ints = (-3, 1, 2, -1, 3, -2, 4)
Output: 4
Count of positive integers: 4
Count of negative integers: 3
Maximum of count of positive and negative integers: 4
Example 2
Input: @ints = (-1, -2, -3, 1)
Output: 3
Count of positive integers: 1
Count of negative integers: 3
Maximum of count of positive and negative integers: 3
Example 3
Input: @ints = (1,2)
Output: 2
Count of positive integers: 2
Count of negative integers: 0
Maximum of count of positive and negative integers: 2
Just looking at this problem I was confident that Raku could solve it in one line and I was right though only if you stretch the definition of one line a bit.
@*ARGS.classify({ if $_ < 0 { q{n} } elsif $_ > 0 { q{p} } else { q{0} } }, :into(my %a)); max(%a<n>.elems, %a<p>.elems).say
The mainstay of this code is the .classify()
method. This takes a subroutine which we provide and runs it on each element in @ints
. Its' output is used as a key into the hash provided by the :into
parameter. In our case the subroutine returns 'n' if the
element is negative and 'p' if it is positive. (We also have to allow for the element being 0 even though the spec doesn't mention it.) So our hash %a
will have two keys (three counting '0' but we're ignoring that,) 'n' and 'p'. Then all we have to do is find
which of those keys was bigger using .max()
and .elems()
and print the result with .say()
.
Perl doesn't have .classify()
so we just loop through @ints
and increment either $positive
or $negative
depending on whether
the element is positive or negative. We don't need to worry about 0 in this method.
my $positive = 0;
my $negative = 0;
for my $n (@ints) {
if ($n > 0) {
$positive++;
} elsif ($n < 0) {
$negative++;
}
}
say 0+($positive > $negative) ? $positive : $negative;
Challenge 2:
Multiply by Two
You are given an array of integers,
@ints
and an integer$k
.Write a script to return the number of pairs (i, j) where
a) 0 <= i < j < size of @ints
b) ints[i] == ints[j]
c) i x j is divisible by k
Example 1
Input: @ints = (3,1,2,2,2,1,3) and $k = 2
Output: 4
(0, 6) => ints[0] == ints[6] and 0 x 6 is divisible by 2
(2, 3) => ints[2] == ints[3] and 2 x 3 is divisible by 2
(2, 4) => ints[2] == ints[4] and 2 x 4 is divisible by 2
(3, 4) => ints[3] == ints[4] and 3 x 4 is divisible by 2
Example 2
Input: @ints = (1,2,3) and $k = 1
Output: 0
This one could possibly be a one-liner too but it seemed simpler and easier to spread it out over multiple lines.
Given @ints
...
@ints
...first we get a list of all the indices of its' elements with .keys()
.
.keys
We find all the combinations of 2 indices with .combinations(2)
.
.combinations(2)
Using .grep()
we filter out the combination where the elements at both indices are equal and the product of those elements
(which we find with the [*]
operator) is divisible by $k
(which we find with the %%
operator.)
.grep({ @ints[@$_[0]] == @ints[@$_[1]] && ([*] @$_) %% $k })
We count how many suitable combinations were found with .elems()
.
.elems
And finally, we print that number with .say()
.
.say;
For Perl we have to provide our own version of combinations()
and workarounds are needed for a lack of [*]
and %%
operators.
say
scalar
grep { $ints[$_->[0]] == $ints[$_->[1]] && ($_->[0] * $_->[1]) % $k == 0 }
combinations([ keys @ints ], 2);