A Bigger Big
with Raku

by Arne Sommer

A Bigger Big with Raku

[392] Published 9. April 2026.

This is my response to The Weekly Challenge #368.

#368.1 Make it Bigger You are given a given a string number and a character digit.

Write a script to remove exactly one occurrence of the given character digit from the given string number, resulting the decimal form is maximised.

Example 1:
Input: $str = "15456", $char = "5"
Output: "1546"

Removing the second "5" is better because the digit following it (6) is
greater than 5. In the first case, 5 was followed by 4 (a decrease),
which makes the resulting number smaller.
Example 2:
Input: $str = "7332", $char = "3"
Output: "732"
Example 3:
Input: $str = "2231", $char = "2"
Output: "231"

Removing either "2" results in the same string here. By removing a "2",
we allow the "3" to move up into a higher decimal place.
Example 4:
Input: $str = "543251", $char = "5"
Output: "54321"

If we remove the first "5", the number starts with 4. If we remove the
second "5", the number still starts with 5. Keeping the largest possible
digit in the highest place value is almost always the priority.
Example 5:
Input: $str = "1921", $char = "1"
Output: "921"

The task can be divided in three cases:

  • The character does not occur in the string [5]
  • The character occurs exactly one time in the string [6]
  • The character occurs more than one time in the string [7]
Let us program it that way:

File: make-it-bigger
#! /usr/bin/env raku

unit sub MAIN ($str is copy where $str  ~~ /^ <[0..9]>+ $/,  # [1]
               $char        where $char ~~ /^ <[0..9]>  $/,  # [2]
               :v(:$verbose));

my $count  = $str.comb.grep( * eq $char ).elems;             # [3]
my $length = $str.chars;                                     # [4]

say ": Count: $count" if $verbose;

if $count == 0                                               # [5]
{
  ;                                                          # [5a]
}
elsif $count == 1                                            # [6]
{
  $str.=trans({ $char => '' });                              # [6a]
}
elsif $count > 1                                             # [7]
{
  for ^$length -> $i                                         # [8]
  {
    say ": str[$i]: { $str.substr($i,1) }" if $verbose;

    if $str.substr($i,1) == $char
  	&& ($i == $length -1 || $str.substr($i+1,1) > $char) # [9]
    {
      say ": Removal to a greater overall value at str[$i]" if $verbose;

      $str.substr-rw($i,1) = "";                             # [10]

      last;                                                  # [10a]
    }
  }

  if $str.chars == $length                                   # [11]
  {
    say ": All removals are bad (value wise), use the last one; \
      the 'lesser bad'" if $verbose;

    $str.substr-rw($str.rindex($char), 1) = "";              # [12]
  }
}

say $str;

[1] The string, containing digits only - and at least one.

[2] A single digit only.

[3] Get the number of times the character occurs in the string.

[4] The length of the string.

[5] No match? Then we do nothing (nothing to remove).

[6] One match? Use trans to swap out the character with an empty string (translate it to a space).

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

[7] More than one match?

[8] Iterate over the indices in the string.

[9] Is the character at the current position the one we are looking for and we are at the last character in the string or the next character is a higher digit than the current one?

[10] Then remove it (with substr-rw), and finish the loop.

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

[11] If the loop was unable to remove a digit (as the next one for all matches had a lower value).

[12] Remove the last one, as that one has the lowest negative impact on the overall value. rindex gives us the last - or rightmost - index.

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

[13] Print the string, modified or not.

Running it:

$ ./make-it-bigger 15456 5
1546

$ ./make-it-bigger 7332 3
732

$ ./make-it-bigger 2231 2
231

$ ./make-it-bigger 543251 5
54321

$ ./make-it-bigger 1921 1
921

Looking good.

With verbose mode:

$ ./make-it-bigger -v 15456 5
: Count: 2
: str[0]: 1
: str[1]: 5
: str[2]: 4
: str[3]: 5
: Removal to a greater overall value at str[3]
1546

$ ./make-it-bigger -v 7332 3
: Count: 2
: str[0]: 7
: str[1]: 3
: str[2]: 3
: str[3]: 2
: All removals are bad (value wise), use the last one; the 'lesser bad'
732

$ ./make-it-bigger -v 2231 2
: Count: 2
: str[0]: 2
: str[1]: 2
: Removal to a greater overall value at str[1]
231

$ ./make-it-bigger -v 543251 5
: Count: 2
: str[0]: 5
: str[1]: 4
: str[2]: 3
: str[3]: 2
: str[4]: 5
: str[5]: 1
: All removals are bad (value wise), use the last one; the 'lesser bad'
54321

$ ./make-it-bigger -v 1921 1
: Count: 2
: str[0]: 1
: Removal to a greater overall value at str[0]
921

Let us make the program shorter. The [5] (no match) and [6] (one match) can be removed, as the [7] block handles those cases. The final check [11] (lesser bad) can be folded into [7].

File: make-it-bigger-shorter
#! /usr/bin/env raku

unit sub MAIN ($str is copy where $str  ~~ /^ <[0..9]>+ $/,
               $char        where $char ~~ /^ <[0..9]>  $/,
               :v(:$verbose));

my $last-resort = $str.rindex($char) // Inf;               # [1]

say ": Index of Last Resort: $last-resort" if $verbose;

for 0 .. $str.chars -1 -> $i
{
  say ": str[$i]: { $str.substr($i,1) }" if $verbose;

  if $str.substr($i,1) == $char
    && ($i == $last-resort || $str.substr($i+1,1) > $char) # [2]
  {
    say ": Removal { $i == $last-resort ?? "of last resort" !! "to a \
      greater overall value { $str.substr($i+1,1) }" } at str[$i]"
        if $verbose;

    $str.substr-rw($i,1) = "";                             # [3]
    last;                                                  # [3a]
  }
}

say $str;                                                  # [4]

[1] Get the last index of the digit to look for; this is the "last resort" for removal. It returns an undefined value on non-match (as 0 is a valid index), so we default to Inf in that case.

[2] Do we have a match and we are at the last resort or the next character is higher than the current one?

[3] Remove the character and exit the loop [3a].

[4] Print the result.

Running it gives the expected result, here with verbose mode:

$ ./make-it-bigger-shorter -v 15456 5
: Index of Last Resort: 3
: str[0]: 1
: str[1]: 5
: str[2]: 4
: str[3]: 5
: Removal of last resort at str[3]
1546

$ ./make-it-bigger-shorter -v 7332 3
: Index of Last Resort: 2
: str[0]: 7
: str[1]: 3
: str[2]: 3
: Removal of last resort at str[2]
732

$ ./make-it-bigger-shorter -v 2231 2
: Index of Last Resort: 1
: str[0]: 2
: str[1]: 2
: Removal of last resort at str[1]
231

$ ./make-it-bigger-shorter -v 543251 5
: Index of Last Resort: 4
: str[0]: 5
: str[1]: 4
: str[2]: 3
: str[3]: 2
: str[4]: 5
: Removal of last resort at str[4]
54321

$ ./make-it-bigger-shorter -v 1921 1
: Index of Last Resort: 3
: str[0]: 1
: Removal to a greater overall value 9 at str[0]
921

We should test the case with only one and zero matches:

$ ./make-it-bigger-shorter -v 12345 3
: Index of Last Resort: 2
: str[0]: 1
: str[1]: 2
: str[2]: 3
: Removal of last resort at str[2]
1245

$ ./make-it-bigger-shorter -v 12345 6
: Index of Last Resort: Inf
: str[0]: 1
: str[1]: 2
: str[2]: 3
: str[3]: 4
: str[4]: 5
12345

#368.2 Big and Little Omega You are given a positive integer $number and a mode flag $mode. If the mode flag is zero, calculate little omega (the count of all distinct prime factors of that number). If it is one, calculate big omega (the count of all prime factors including duplicates).

Example 1:
Input: $number = 100061
       $mode = 0
Output: 3

Prime factors are 13, 43, 179. Count is 3.
Example 2:
Input: $number = 971088
       $mode = 0
Output: 3

Prime factors are 2, 2, 2, 2, 3, 20231. Count of distinct numbers is 3.
Example 3:
Input: $number = 63640
       $mode = 1
Output: 6

Prime factors are 2, 2, 2, 5, 37, 43. Count including duplicates is 6.
Example 4:
Input: $number = 988841
       $mode = 1
Output: 2
Example 5:
Input: $number = 211529
       $mode = 0
Output: 2

My «factors» procedure, introduced in Centenary Sequences with Raku - Part 5: Divisors and Factors is reused here.

File: balo
#! /usr/bin/env raku

unit sub MAIN (Int $number where $number > 0,          # [1]
               Int $mode where $mode == any(0|1),      # [2]
	       :v(:$verbose));

my @factors = factors($number);                        # [3]

say ": Factors: { @factors.join(",") }" if $verbose;

say $mode ?? @factors.elems !! @factors.unique.elems;  # [4]

sub factors ($number is copy)
{
  return (1)       if $number == 1;
  return ($number) if $number.is-prime;

  my @factors;

  for (2 .. $number div 2).grep( *.is-prime ) -> $candidate
  {
    while $number %% $candidate
    {
      @factors.push: $candidate;
      $number /= $candidate;
    }
  }
    
  return @factors;
}

[1] A positive integer.

[2] A mode digit of 0 or 1 only.

[3] Get all the prime factors.

[4] Count them all, or just the distinct (unique) ones, depending on the mode.

Running it:

$ ./balo 100061 0
3

$ ./balo 971088 0
3

$ ./balo 63640 1
6

$ ./balo 988841 1
2

$ ./balo 211529 0
2

Looking good.

With verbose mode:

$ ./balo -v 100061 0
: Factors: 13,43,179
3

$ ./balo -v 971088 0
: Factors: 2,2,2,2,3,20231
3

$ ./balo -v 63640 1
: Factors: 2,2,2,5,37,43
6

$ ./balo -v 988841 1
: Factors: 7,141263
2

$ ./balo -v 211529 0
: Factors: 37,5717
2

And that's it.