PWC197 - Move Zero

TL;DR

Here we are with TASK #1 from The Weekly Challenge #197. Enjoy!

The challenge

You are given a list of integers, @list.

Write a script to move all zero, if exists, to the end while maintaining the relative order of non-zero elements.

Example 1

Input:  @list = (1, 0, 3, 0, 0, 5)
Output: (1, 3, 5, 0, 0, 0)

Example 2

Input: @list = (1, 6, 4)
Output: (1, 6, 4)

Example 3

Input: @list = (0, 1, 0, 2, 0
Output: (1, 2, 0, 0, 0)

The questions

Should we preserve the input @list or should we modify it in-place? I’ll go with the modification alternative.

The solution

The algorithm will be the same:

  • iterate using an index in the array, starting from index 0
  • if the current index points to a zero, it is removed (via splice) and the index is kept still (because the rest of the array shifts to the left)
  • otherwise, we advance the index.

Raku:

#!/usr/bin/env raku
use v6;
sub MAIN (*@args) {
   @args = <1 0 3 0 0 5>».Int unless @args;
   put '(', move-zero-in-place(@args).join(', '), ')';
}

sub move-zero-in-place (@list) {
   my $i = 0;
   my $n-zeros = 0;
   while $i < @list {
      if @list[$i] == 0 {
         ++$n-zeros;
         @list.splice($i, 1);
      }
      else { ++$i }
   }
   @list.push: |(0 xx $n-zeros);
   return @list;
}

Perl:

#!/usr/bin/env perl
use v5.24;
use warnings;
use experimental 'signatures';
no warnings 'experimental::signatures';

@ARGV = qw< 1 0 3 0 0 5 > unless @ARGV;
move_zero_in_place(\@ARGV);
{ local $" = ', '; say "(@ARGV)" }

sub move_zero_in_place ($list) {
   my $i = 0;
   my $n_zeros = 0;
   while ($i < $list->@*) {
      if ($list->[$i] == 0) {
         ++$n_zeros;
         splice $list->@*, $i, 1;
      }
      else { ++$i }
   }
   push $list->@*, (0) x $n_zeros;
   return $list;
}

Stay safe folks!


Comments? Octodon, Twitter, GitHub, Reddit, or drop me a line!