Counter Nice
with Raku

by Arne Sommer

Counter Nice with Raku

[351] Published 13. July 2025.

This is my response to The Weekly Challenge #329.

Challenge #329.1: Counter Integers

You are given a string containing only lower case English letters and digits.

Write a script to replace every non-digit character with a space and then return all the distinct integers left.

Example 1:
Input: $str = "the1weekly2challenge2"
Output: 1, 2

2 is appeared twice, so we count it one only.
Example 2:
Input: $str = "go21od1lu5c7k"
Output: 21, 1, 5, 7
Example 3:
Input: $str = "4p3e2r1l"
Output: 4, 3, 2, 1

I cannot see any reason to replace the non-digit characters with a space, as the spaces are not used for anything later on. The second step would then be splitting the string on spaces, but we can skip this trip to space by just splitting the original string on the lowercase letters.

File: counter-integers
#! /usr/bin/env raku

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

my @ints = $str.split(/<[a..z]>+/).grep: * ~~ /\d+/;       # [2]

say ": Integers: { @ints.join(", ") }" if $verbose;

say @ints.unique.join(", ");                               # [3]

[1] Ensure lowercase letters and digit only, with at least one of them.

[2] The letters are ignoreable (i.e. junk), so we can split on them to get a list of consecutive digits. The trailing grep is there to get rid of a leading (if the string started with a digit) or trailing (if it ended with a digit) empty element.

[3] Get rid of duplicate integers with unique, and print the result.

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

Running it:

$ ./counter-integers the1weekly2challenge2
1, 2

$ ./counter-integers go21od1lu5c7k
21, 1, 5, 7

$ ./counter-integers 4p3e2r1l
4, 3, 2, 1

Looking good.

With verbose mode:

$ ./counter-integers -v the1weekly2challenge2
: Integers: 1, 2, 2
1, 2

$ ./counter-integers -v go21od1lu5c7k
: Integers: 21, 1, 5, 7
21, 1, 5, 7

$ ./counter-integers -v 4p3e2r1l
: Integers: 4, 3, 2, 1
4, 3, 2, 1

Challenge #329.2: Nice String

You are given a string made up of lower and upper case English letters only.

Write a script to return the longest substring of the give string which is nice. A string is nice if, for every letter of the alphabet that the string contains, it appears both in uppercase and lowercase.

Example 1:
Input: $str = "YaaAho"
Output: "aaA"
Example 2:
Input: $str = "cC"
Output: "cC"
Example 3:
Input: $str = "A"
Output: ""

No nice string found.
File: nice-string
#! /usr/bin/env raku

unit sub MAIN ($str where $str ~~ /^<[ a..z A .. Z ]>+$/,     # [1]
               :v(:$verbose));

my @str     = $str.comb;                                      # [2]
my $current = @str.shift;                                     # [3]
my @nice;                                                     # [4]

while @str.elems                                              # [5]
{
  if @str[0].lc eq $current.substr(0,1).lc                    # [6]
  {
    $current ~= @str.shift;                                   # [7]
  }
  else                                                        # [8]
  {
    @nice.push: $current if $current.comb.unique.elems == 2;  # [9]
    $current = @str.shift;                                    # [10]
  }
}

@nice.push($current) if $current.comb.unique.elems == 2;      # [11]

say ": Nice: { @nice.join(", ") }" if $verbose;

@nice .= sort({ $^b.chars <=> $^a.chars });                   # [12]

say ": Nice by length: { @nice.join(", ") }" if $verbose;

say @nice.first // "";                                        # [13]

[1] Ensure lower- and uppercase letters only; at least one.

[2] Get a list of single characters.

[3] The current character.

[4] The nice strings will end up here.

[5] As long as we have more letters to process.

[6] Is the lowercase version of the next letter (@str[0].lc) identical to the current letter (which may be a string, so we get the first one with substr).

[7] • Add the next letter to the current string (and remove it from the list).

[8] If not,

[9] • We are starting on a new nice string. Add the previous one to the list, but only if it has both a lower- and an uppercase letter. This is done by checking that we have two unique characters (as they are identical if we ignore the case).

[10] • Prepare for the next iteration.

[11] No more unfinished letters, but we have to add a final nice string.

[12] Sort the list of nice strings by their lengths; with the longest first.

[13] Print the longest (i.e. first in the list), and default to an empty string in the absence of any nice strings.

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

Running it:

$ ./nice-string YaaAho
aaA

$ ./nice-string cC
cC

9 $ ./nice-string A

Looking good.

With verbose mode:

$ ./nice-string -v YaaAho
: Nice: aaA
: Nice by length: aaA
aaA

$ ./nice-string -v cC
: Nice: cC
: Nice by length: cC
cC

9 $ ./nice-string -v A
: Nice: 
: Nice by length: 

And that's it.