Perl Weekly Challenge: Week 40
Challenge 1:
Show Multiple Arrays Content
You are given two or more arrays. Write a script to display values of each list at a given index.
For example:
Array 1: [ I L O V E Y O U ]
Array 2: [ 2 4 0 3 2 0 1 9 ]
Array 3: [ ! ? £ $ % ^ & * ]
We expect the following output:
I 2 ! L 4 ? O 0 £ V 3 $ E 2 % Y 0 ^ O 1 & U 9 *
Raku makes this easy with the [Z]
operator.
multi sub MAIN() {
my @array1 = < I L O V E Y O U >;
my @array2 = < 2 4 0 3 2 0 1 9 >;
my @array3 = < ! ? £ $ % ^ & * >;
for [Z] @array1, @array2, @array3 -> @i {
@i.join(q{ }).say;
}
}
Perl doesn't have [Z]
so I wrote a function to emulate it.
sub Z {
my $numArrays = scalar @_;
my @result;
for my $i (0 .. scalar @{ $_[0] } - 1) {
my @row;
for my $j (0 .. $numArrays - 1) {
push @row, $_[$j]->[$i];
}
push @result, \@row;
}
return @result;
}
The rest works the same as in Raku.
my @array1 = (qw/ I L O V E Y O U /);
my @array2 = (qw/ 2 4 0 3 2 0 1 9 /);
my @array3 = (qw/ ! ? £ $ % ^ & * /);
for my $i (Z(\@array1, \@array2, \@array3)) {
say join q{ }, @{ $i };
}
Challenge 2:
Sort SubList
You are given a list of numbers and set of indices belong to the list. Write a script to sort the values belongs to the indices.
For example,
List: [ 10, 4, 1, 8, 12, 3 ]
Indices: 0,2,5
We would sort the values at indices 0, 2 and 5 i.e. 10, 1 and 3.
Final list would look like below:
List: [ 1, 4, 3, 8, 12, 10 ]
Perl solution first. These are my list and indices.
my @list = ( 10, 4, 1, 8, 12, 3 );
my @indices = ( 0, 2, 5 );
The answer is basically a one-liner but it is the kind of forbidding-looking code that gives Perl a bad reputation for readability though I must say it looks fine to me. In any case, in order to make it more legible, I've split the code over four lines.
map { state $i = 0; $list[$indices[$i++]] = $_; }
sort { $a <=> $b }
map { $list[$_] }
@indices;
To explain it, we have to go in reverse order.
map { $list[$_] }
@indices;
...takes our list of indices and generates an array of values from the @list
at those
indices.
sort { $a <=> $b }
...sorts that array numerically as the spec requires.
map { state $i = 0; $list[$indices[$i++]] = $_; }
... takes consecutive values from that array and assigns them back into the list
at the appropriate place. But how do we know which is the appropriate place? Well,
we have to step through @indices
but we are currently stepping through the array
of sorted values assembled above. So I defined a state variable (what is known as
a static variable in C/C++) to act as a counter.
Finally, we display the now sorted list.
say join q{ }, @list;
Translating the Perl version into Raku was fairly straightforward. One small hiccup I
had was in map()
ing the array of sorted sublist values. I had to wrap that
part in []
to make the map work on the right values. This is the final version:
my @list = < 10 4 1 8 12 3 >;
my @indices = < 0 2 5 >;
[ @indices.map({ @list[$_] }).sort ]
.map({ state $i = 0; @list[@indices[$i]] = $_; $i++;});
@list.join(q{ }).say;