Perl Weekly Challenge: Week 263
Challenge 1:
Target Index
You are given an array of integers,
@ints
and an integer$k
.Write a script to return the list of indices in the sorted array where the element is same as the given target element.
Example 1
Input: @ints = (1, 5, 3, 2, 4, 2), $k = 2
Output: (1, 2)
Sorted array: (1, 2, 2, 3, 4, 5)
Target indices: (1, 2) as $ints[1] = 2 and $ints[2] = 2
Example 2
Input: @ints = (1, 2, 4, 3, 5), $k = 6
Output: ()
No element in the given array matching the given target.
Example 3
Input: @ints = (5, 3, 2, 4, 2, 1), $k = 4
Output: (4)
Sorted array: (1, 2, 2, 3, 4, 5)
Target index: (4) as $ints[4] = 4
Not a one-liner this week but it's close.
First we create a sorted version of @ints
which is dead simple with .sort()
.
my @sorted = @ints.sort;
Then we get all the indices of the elements of @sorted
and go through the array with .grep()
finding the indices whose corresponding elements equal $k
. The rest of the code is just for pretty-printing these indices in the same format as the examples.
say q{(}, @sorted.keys.grep({ @sorted[$_] == $k}).join(q{, }), q{)};
The Perl version is almost the same except the order of operations is right to left. Having chained code operations read from left to right is just of the many simple but nice quality of life improvements that Raku provides over Perl. (Though Arabic or Hebrew speakers might not agree.)
my @sorted = sort { $a <=> $b } @ints;
say q{(}, (join q{, }, grep { $sorted[$_] == $k} keys @sorted), q{)};
Challenge 2:
Merge Items
You are given two 2-D array of positive integers,
$items1
and$items2
where element is pair of (item_id, item_quantity).Write a script to return the merged items.
Example 1
Input: $items1 = [ [1,1], [2,1], [3,2] ]
$items2 = [ [2,2], [1,3] ]
Output: [ [1,4], [2,3], [3,2] ]
Item id (1) appears 2 times: [1,1] and [1,3]. Merged item now (1,4)
Item id (2) appears 2 times: [2,1] and [2,2]. Merged item now (2,3)
Item id (3) appears 1 time: [3,2]
Example 2
Input: $items1 = [ [1,2], [2,3], [1,3], [3,2] ]
$items2 = [ [3,1], [1,3] ]
Output: [ [1,8], [2,3], [3,3] ]
Example 3
Input: $items1 = [ [1,1], [2,2], [3,3] ]
$items2 = [ [2,3], [2,4] ]
Output: [ [1,1], [2,9], [3,3] ]
First a hash is created to store the merged items. Its' keys will be the items ids, and the values will be the items quantity.
my %merged;
Getting the command-line input into the script is the hardest part of the solution really. I chose to have the input (for e.g. example 1) look like this: "1,1 2,1 3,2" "2,2 1,3". $items1
and $items2
can be concatenated as they will be treated exactly
the same in the merge process. Once we have .split()
and .map()
ed the input into individual items...
for "$items1 $items2".split(/\s+/).map({ $_.split(/\,/) }) -> $item {
...item is added to %merged
.
%merged{@$item[0]} += @$item[1];
}
Once all items are processed, we should have a hash whose keys are unique item ids and whose values are cumulative total item quantities.
This next bit looks complicated but it is mainly because I was trying to format the output in the style of the examples.
say q{[ },
%merged
The only important part is this line which .sort()
s the %merged
hash in numeric ascending order.
.sort
.map({ "[{$_.key},{$_.value}]" })
.join(q{, }),
q{ ]};
And this is the Perl version.
my %merged;
foreach my $item (map { [split /\,/] } split /\s+/, "$items1 $items2") {
$merged{$item->[0]} += $item->[1];
}
say q{[ },
(join q{, }, map { "[$_,$merged{$_}]" } sort { $merged{$b} <=> $merged{$a} } keys %merged),
q{ ]};