## 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.

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.