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.