Decoded Order
with Raku

by Arne Sommer

Decoded Order with Raku

[415] Published 13. September 2026.

This is my response to The Weekly Challenge #390.

#390.1 Decode String You are given an encoded string.

Write a script to return the decoded string of the given encoded string.

The encoding rule is: K[encoded_string], where the encoded_string inside the square brackets is repeated exactly K > 0 times.

Example 1:
Input: $str = "2[3[a]]"
Output: "aaaaaa"

3[a]    => aaa
2[3[a]] => aaa aaa
Example 2:
Input: $str = "10[a]"
Output: "aaaaaaaaaa"
Example 3:
Input: $str = "a2[b]c3[d]e"
Output: "abbcddde"
Example 4:
Input: $str = "2[a2[b]c]"
Output: "abbcabbc"
Example 5:
Input: $str = "1[a]2[b3[c]]"
Output: "abcccbccc"
File: decode-string
#! /usr/bin/env raku

unit sub MAIN (Str $str is copy, :v(:$verbose));

say ": $str" if $verbose;

while $str ~~ / \d+ \[ /
{
  $str ~~
    s[ $<k> = \d+ \[ $<s> = <-[\[\]]>* \] ] = ~$<s> x $<k>.Int;

  say ": $str" if $verbose;
}

say $str;

[3] Note the use if is copy so that we get a writeable copy of the input.

See docs.raku.org/type/Parameter#method_copy for more information about is copy.

[7] As long as the string contains a digit immediately followed by an opening bracket.

[9] Find the first group whose content does not contain any brackets - i.e. an innermost group. This regex does the job: $<k> = \d+ \[ $<s> = <-[\[\]]>* \]. Note that $<k> is the repetition count, and $<s> is the bracket-free content.

Then replace that group (using the substitution operator s) with its content repeated k times, in s[ ... ] = ~$<s> x $<k>.Int.

See docs.raku.org/syntax/s/// for more information about the substitution operator s///.

[15] Print the result.

Running it:

$ ./decode-string "2[3[a]]"
aaaaaa

$ ./decode-string "10[a]"
aaaaaaaaaa

$ ./decode-string "a2[b]c3[d]e"
abbcddde

$ ./decode-string "2[a2[b]c]"
abbcabbc

$ ./decode-string "1[a]2[b3[c]]"
abcccbccc

Looking good.

With verbose mode:

$ ./decode-string -v "2[3[a]]"
: 2[3[a]]
: 2[aaa]
: aaaaaa
aaaaaa

$ ./decode-string -v "10[a]"
: 10[a]
: aaaaaaaaaa
aaaaaaaaaa

$ ./decode-string -v "a2[b]c3[d]e"
: a2[b]c3[d]e
: abbc3[d]e
: abbcddde
abbcddde

$ ./decode-string -v "2[a2[b]c]"
: 2[a2[b]c]
: 2[abbc]
: abbcabbc
abbcabbc

$ ./decode-string -v "1[a]2[b3[c]]"
: 1[a]2[b3[c]]
: a2[b3[c]]
: a2[bccc]
: abcccbccc
abcccbccc

#390.2 Order Characters You are given a string $s (containing only alphabetic characters) and an integer $k > 0.

Write a script to choose one of the first $k letters of given string and append it at the end of the string. You keep doing this until you have lexicographically smallest string and return the string.

Example 1:
Input: $str = "dbca", $k = 1
Output: "adbc"

Move 1: "bcad"
Move 2: "cadb"
Move 3: "adbc"
Example 2:
Input: $str = "geeks", $k = 2
Output: "eegks"

First 2 letters: "g", "e"

Move 1: "gekse" (move second letter "e")
Move 2: "gksee" (move second letter "e")
Move 3: "kseeg"
Move 4: "seegk"
Move 5: "eegks"
Example 3:
Input: $str = "cbaed", $k = 3
Output: "abcde"

First 3 letters: "c", "b", "a"

Move 1: "cbeda"  (move "a")
Move 2: "cedab"  (move "b")
Move 3: "edabc"  (move "c")
Move 4: "eabcd"  (move "d")
Move 5: "abcde"  (move "e")
Example 4:
Input: $str = "fedcba", $k = 4
Output: "abcdef"

First 4 letters: "f", "e", "d", "c"

Move 1: "fdcbae" (move "e")
Move 2: "dcbaef" (move "f")
Move 3: "dcbefa" (move "a")
Move 4: "dcefab" (move "b")
Move 5: "defabc" (move "c")
Move 6: "efabcd" (move "d")
Move 7: "fabcde" (move "e")
Move 8: "abcdef" (move "f")
Example 5:
Input: $str = "perl", $k = 1
Output: "erlp"

Move 1: "erlp" (move "p")
Example 6:
Input: $str = "oloolooo", $k = 1
Output: "looloooo"
Example 7:
Input: $str = "oloooolo", $k = 1
Output: "looloooo"

This is really easy, if we disregard the instruction to actually move one character at a time until we reach the target. But let us have a go at following instructions...

  • If $k==1, the answer is just the lowest sorted rotated version of the input
  • If $k>1, the answer is the string with the characters reordered in sorted order
File: order-characters-okish
#! /usr/bin/env raku

unit sub MAIN (Str $str is copy where $str ~~ /<[a..zA..Z]>/,
               Int $k where $str.chars >= $k > 0,
               :a(:$all),
               :v(:$verbose) = $all);

my $result;

if $k == 1
{
  my @rotations = map { $str.substr($_) ~ $str.substr(0, $_) },
                      0 ..^ $str.chars;

  say ": rotations: " ~ @rotations.raku if $verbose;

  $result = @rotations.min;

  while $all && $str ne $result
  {
    $str = $str.substr(1) ~ $str.substr(0, 1);

    say ": -> $str" if $verbose;
  }
}
else
{
  $result = $str.comb.sort.join;

  while $all && $str ne $result
  {
    my $index = $str.index($str.substr(0, $k).comb.min);
    
    $str ~= $str.substr($index, 1);

    $str.substr-rw($index, 1) = "";

    say ": index $index -> $str" if $verbose;
  }
}

say $result;

[5] Use «all mode» to get the actual moves. It enables «verbose mode» as well.

[8] The result will end up here.

[10] If we are only allowed to move the first.

[12] Get all the rotations of the input.

[17] The result is the minimum string, as min works on strings and not just numbers.

See docs.raku.org/routine/min for more information about min.

This is where this program fails. In the second example, moving the lowest character is ok, until the last move. Then we should move the highest. But I have run out of time, so haven't figured out when to switch.

Do not use «all mode» when $k > 1, as that will lead to an eternal loop.

[19] If you want to see the rotations, use «all mode». The loop goes on until we reach the target.

[21] Move the first character to the end.

[26] When k > 1:

[28] The result is the sorted string.

[30] As long as we have not reached the target.

[32] Get the index of the character to move. I have chosen to move the lowest (gotten with min).

[34] Add the moved character at the end.

[36] Remove it from the original position, with substr-rw that allows us to replace it (in this ase with an empty string).

See docs.raku.org/routine/substr-rw for more information about substr-rw.

[42] Print the result.

Running it:

$ ./order-characters-okish dbca 1
adbc

$ ./order-characters-okish geeks 2
eegks

$ ./order-characters-okish cbaed 3
abcde

$ ./order-characters-okish fedcba 4
abcdef

$ ./order-characters-okish perl 1
erlp

$ ./order-characters-okish oloolooo 1
looloooo

$ ./order-characters-okish oloooolo 1
looloooo

Looking good.

With all (and verbose) mode, but only for the ones with $k==1:

$ ./order-characters-okish -a dbca 1
: rotations: ["dbca", "bcad", "cadb", "adbc"]
: -> bcad
: -> cadb
: -> adbc
adbc

$ ./order-characters-okish -a perl 1
: rotations: ["perl", "erlp", "rlpe", "lper"]
: -> erlp
erlp

$ ./order-characters-okish -a oloolooo 1
: rotations: ["oloolooo", "looloooo", "oolooool", "oloooolo", "looooloo",
  "oooolool", "oooloolo", "oolooloo"]
: -> looloooo
looloooo

$ ./order-characters-okish -a oloooolo 1
: rotations: ["oloooolo", "looooloo", "oooolool", "oooloolo", "oolooloo",
  "oloolooo", "looloooo", "oolooool"]
: -> looooloo
: -> oooolool
: -> oooloolo
: -> oolooloo
: -> oloolooo
: -> looloooo
looloooo

And that's it.