Perl Weekly Challenge: Week 226
Challenge 1:
Shuffle String
You are given a string and an array of indices of same length as string.
Write a script to return the string after re-arranging the indices in the correct order.
Example 1
Input: $string = 'lacelengh', @indices = (3,2,0,5,4,8,6,7,1)
Output: 'challenge'
Example 2
Input: $string = 'rulepark', @indices = (4,7,3,1,0,5,2,6)
Output: 'perlraku'
Alas, in a break with long-standing tradition, challenge 1 will not be solved with a one-liner this week. But this solution is also pretty straightforward.
First we split the $string
up into a list of individual letters.
my @letters = $string.comb;
We will also need a list to store the result.
my @result;
Using the Z
or zip operator, we form pairs of a letter from @letters
and the index in the equivalent
position in @indices
then place the letter at that index in @result
.
for @letters Z @indices -> ($letter, $index) {
@result[$index] = $letter;
}
Then all we need to do is join @results up into a string and print it.
@result.join.say;
The Perl version is similar.
my @letters = split //, $string;
my @result;
In the absence of Z
we just loop through the indexes of @indices
and use that to find the equivalent position in @letters.
So this won't work if @letters
and @indices
are of different length. That's not something we need to worry about for
the examples though.
for my $i (0 .. scalar @indices - 1) {
$result[$indices[$i]] = $letters[$i];
}
say join q{}, @result;
Challenge 2:
Zero Array
You are given an array of non-negative integers, @ints.
Write a script to return the minimum number of operations to make every element equal zero.
In each operation, you are required to pick a positive number less than or equal to the smallest element in the array, then subtract that from each positive element in the array.
Example 1
Input: @ints = (1, 5, 0, 3, 5)
Output: 3
operation 1: pick 1 => (0, 4, 0, 2, 4)
operation 2: pick 2 => (0, 2, 0, 0, 2)
operation 3: pick 2 => (0, 0, 0, 0, 0)
Example 2
Input: @ints = (0)
Output: 0
Example 3
Input: @ints = (2, 1, 4, 0, 3)
Output: 4
operation 1: pick 1 => (1, 0, 3, 0, 2)
operation 2: pick 1 => (0, 0, 2, 0, 1)
operation 3: pick 1 => (0, 0, 1, 0, 0)
operation 4: pick 1 => (0, 0, 0, 0, 0)
We start the Raku solution by assigning storage for a count of operations that might be performed.
my $ops = 0;
Then until all elements of @ints
equal 0...
until @ints.all == 0 {
...we find the smallest element of @ints
with .min()
after filtering out all the 0's with .grep()
so we don't
get 0 every time.
my $pick = @ints.grep({ $_ != 0 }).min;
Then we transform @ints
with .map()
so that each non-zero element is reduced by the value of $pick
.
@ints = @ints.map({ $_ == 0 ?? 0 !! $_ - $pick });
This is one operation as the spec calls it so we increment $ops
.
$ops++;
}
And finally we print out how many operations were performed.
say $ops;
The spec wasn't clear as to what should happen if one of the elements of @ints
becomes negative as a result of an operation.
This doesn't occur in any of the examples so I didn't think about it any further.
This is the Perl version.
my $ops = 0;
while (scalar grep {$_ != 0} @ints) {
I got around Perls' lack of .min()
by sorting the non-zero elements of @ints
and taking the first element which will be
the smallest.
my $pick = [sort { $a <=> $b } grep { $_ != 0 } @ints]->[0];
@ints = map { $_ == 0 ? 0 : $_ - $pick } @ints;
$ops++;
}
say $ops;