Perl Weekly Challenge 226: Shuffle String
These are some answers to the Week 226, Task 1, of the Perl Weekly Challenge organized by Mohammad S. Anwar.
Spoiler Alert: This weekly challenge deadline is due in a few days from now (on July 23, 2023 at 23:59). This blog post offers some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.
Task 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'
I first thought that the indice
represented the order in which to pick the letters from the string, and quickly came up with the following simple Raku subroutine:
sub shuffle-string ($string, @indices) {
# Caution: wrong solution
return ($string.comb)[@indices].join("");
}
and ran it with the first example provided with task:
$string = 'lacelengh', @indices = (3,2,0,5,4,8,6,7,1)
But that doesn't work, as, instead of "challenge", it returns the following string:
eclelhnga
What the heck is this? After some checks, I quickly came to the conclusion that my program did not appear to be buggy, but that I had misunderstood the task. How the hell can we obtain the string "challenge" from the given input data? It took me a few minutes to understand. Looking at the letters of the input string and the input indice:
[l a c e l e n g h]
(3 2 0 5 4 8 6 7 1)
we can see that it works differently: we need to pick the letter whose position is that of 0 in the indice (i.e. 'c'), then the letter whose position is that of 1 in the indice, and so on:
0 c
1 h
2 a
3 l
4 l
5 e
6 n
7 g
8 e
So we need to transform the input @indice
array, or reverse it if you prefer, if we want to use it as a "slice" on the array containing the letters of the input string. The idea is to construct a new array where the first integer will be the position corresponding to 0 in the original @indice
array (i.e. letter 'c'), the second item will be the position corresponding to 1 in the original @indice
array (letter 'h'), and so on so that we will end up with the following new array:
[2 8 1 0 4 3 6 7 5]
which can readily used as a slice over the arrays of letters of the original string.
Shuffle String in Raku
Please refer to the above explanations to understand the array transformation (@indices -> @index
) performed by the program.
sub shuffle-string ($string, @indice) {
my @index;
@index[@indice[$_]]= $_ for 0..@indice.end;
# say @index;
return ($string.comb)[@index].join("");
}
for ('lacelengh', (3,2,0,5,4,8,6,7,1)),
('rulepark', (4,7,3,1,0,5,2,6)) -> @test {
printf "%-10s - %-20s => ", @test[0], "@test[1]";
say shuffle-string @test[0], @test[1];
}
This program displays the following output:
$ raku ./shuffle-string.raku
lacelengh - 3 2 0 5 4 8 6 7 1 => challenge
rulepark - 4 7 3 1 0 5 2 6 => perlraku
Shuffle String in Perl
This a port to Perl of the above Raku program. Please refer to the explanations after the task description if you need any further explanation.
use strict;
use warnings;
use feature 'say';
sub shuffle_string {
my ($string, $idx_ref) = @_;
my @indices = @$idx_ref;
my @index;
@index[$indices[$_]]= $_ for 0..$#indices;
return join "", (split //, $string)[@index];
}
for my $test (['lacelengh', [3,2,0,5,4,8,6,7,1]],
['rulepark', [4,7,3,1,0,5,2,6]]) {
printf "%-10s - %-18s => ",
$test->[0], "@{$test->[1]}";
say shuffle_string $test->[0], $test->[1];
}
This program displays the following output:
$ perl ./shuffle-string.pl
lacelengh - 3 2 0 5 4 8 6 7 1 => challenge
rulepark - 4 7 3 1 0 5 2 6 => perlraku
Wrapping up
The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on July 30 , 2023. And, please, also spread the word about the Perl Weekly Challenge if you can.
Leave a comment