One Zero
with Raku

by Arne Sommer

One Zero with Raku

[255] Published 22. September 2023.

This is my response to The Weekly Challenge #235.

Challenge #235.1: Remove One

You are given an array of integers.

Write a script to find out if removing ONLY one integer makes it strictly increasing order.

Example 1:
Input: @ints = (0, 2, 9, 4, 6)
Output: true

Removing ONLY 9 in the given array makes it strictly increasing order.
Example 2:
Input: @ints = (5, 1, 3, 2)
Output: false
Example 3:
Input: @ints = (2, 2, 3)
Output: true
File: remove-one
#! /usr/bin/env raku

unit sub MAIN (*@ints where all(@ints) ~~ Int, :v(:$verbose));  # [1]

# ( say 'true'; exit ) if [<] @ints;                            # [2]

for 0 .. @ints.end -> $index                                    # [3]
{
  my @copy = @ints.clone;                                       # [4]
  @copy.splice($index,1);                                       # [5]
  say ":Index $index: remove value @ints[$index] -> @copy[]" if $verbose;
  ( say 'true'; exit ) if [<] @copy;                            # [6]
}

say 'false';                                                    # [7]

[1] One or more integers.

[2] Are they sorted already? This is easy to ascertain with the Reduction Metaoperator [] in combination with < (the "less than" operator). If so, we are done. (Note that I have commented out this line of code as this situation will be catched by the very first iteration of the loop [3].)

See docs.raku.org/language/operators#Reduction_metaoperators for more information about the Reduction Metaoperator [].

[3] Iterate over the indices in the input. (Note that for ^@ints.elems -> $index would work just as well).

[4] Get a copy (with clone), so that we can change it (the copy), without messing up the original.

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

[5] Remove the (as in "one") element at the given index (with splice).

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

[6] Have we succeeded? If so, say so and exit.

[7] Not succeeded by now? Then we have failed. Say so

Running it:

$ ./remove-one 0 2 9 4 6
true

$ ./remove-one 5 1 3 2
false

$ ./remove-one 2 2 3
true

Looking good.

With verbose mode:

$ ./remove-one -v 0 2 9 4 6
:Index 0: remove value 0 -> 2 9 4 6
:Index 1: remove value 2 -> 0 9 4 6
:Index 2: remove value 9 -> 0 2 4 6
true

$ ./remove-one -v 5 1 3 2
:Index 0: remove value 5 -> 1 3 2
:Index 1: remove value 1 -> 5 3 2
:Index 2: remove value 3 -> 5 1 2
:Index 3: remove value 2 -> 5 1 3
false

$ ./remove-one -v 2 2 3
:Index 0: remove value 2 -> 2 3
true

Challenge #235.2: Duplicate Zeros

You are given an array of integers.

Write a script to duplicate each occurrence of ZERO in the given array and shift the remaining to the right but make sure the size of array remain the same.

Example 1:
Input: @ints = (1, 0, 2, 3, 0, 4, 5, 0)
Ouput: (1, 0, 0, 2, 3, 0, 0, 4)
Example 2:
Input: @ints = (1, 2, 3)
Ouput: (1, 2, 3)
Example 3:
Input: @ints = (0, 3, 0, 4, 5)
Ouput: (0, 0, 3, 0, 0)

This task is ideally suited for gather/take.

See my Raku Gather, I Take article or docs.raku.org/syntax/gather take for more information about gather/take.

File: duplicate-zeros
#! /usr/bin/env raku

unit sub MAIN (*@ints where all(@ints) ~~ Int);  # [1]

my $seq := gather                                # [2]
{
  for @ints -> $int                              # [3]
  {
    take $int;                                   # [4]
    take $int if $int == 0;                      # [5]
  }
}

say "({ $seq[^@ints.elems].join(", ") })";       # [6]

[1] Zero or more integers.

[2] Set up a sequence with gather.

[3] Iterate over the input values.

[4] Let each value pass through (to the output sequence) with take.

[5] Add an extra zero (with take), if the input value is zero.

[6] Collect as many values from the output sequence, as we have in the input, and pretty print them. The sequence is lazy, so the program will not pass through (generate with take) any more values than requested.

Running it:

$ ./duplicate-zeros 1 0 2 3 0 4 5 0
(1, 0, 0, 2, 3, 0, 0, 4)

$ ./duplicate-zeros 1 2 3
(1, 2, 3)

$ ./duplicate-zeros 0 3 0 4 5
(0, 0, 3, 0, 0)

Looking good.

And that's it.