Perl Weekly Challenge: Week 197

I'm back from my trip to India and eager to catch up with the challenges I missed while I was gone. So without further ado...

Challenge 1:

Move Zero

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)

This one is pretty straightforward.

First we set up two arrays, one to hold the 0's and one for every other number.

my @zeros;
my @numbers;

Then we iterate through the elements of @list.

for @list -> $i {

If the value of the element is 0, we add it to the @zeros array...

    if $i == 0 {
        @zeros.push($i)

...or if it isn't we add it to the @numbers array.

    } else {
        @numbers.push($i)
    }
}

Finally we append @zeros to @numbers (remembering to flatten the appended values with |.) The rest of this line is to make the output look like that in the spec.

say q{(}, @numbers.push(| @zeros).join(q{, }), q{)};

(Full code on Github.)

This is the Perl version which works the same way.

my @zeros;
my @numbers;

for my $i (@list) {
    if ($i == 0) {
        push @zeros, $i;
    } else {
        push @numbers, $i;
    }
}

push @numbers, @zeros;
say q{(}, (join q{, }, @numbers), q{)};

(Full code on Github.)

Challenge 2:

Wiggle Sort

You are given a list of integers, @list.

Write a script to perform Wiggle Sort on the given list.

Wiggle sort would be such as list[0] < list[1] > list[2] < list[3]….

Example 1
Input: @list = (1,5,1,1,6,4)
Output: (1,6,1,5,1,4)
Example 2
Input: @list = (1,3,2,2,3,1)
Output: (2,3,1,3,1,2)

Umm, I'm not sure I got this one right but anyway here is my attempt in Raku.

It feels a bit like cheating if we use .sort() to implement a sort algorithm but this seemed to be the easiest way to get all the elements of @list in numeric order, smallest value to largest.

@list = @list.sort({ $^a <=> $^b });

The middle element of the sorted list is identified.

my $mid = @list.elems div 2;

An array is declared to hold the wiggle sorted array.

my @sorted;

We will also need to know if our @list has an odd number of elements or not.

my $odd = @list.elems % 2 == 1;

If there are an odd number of elements, the first one to be added to @sorted.

if $odd {
    @sorted.push(@list[$mid]);
}

Next, we are going to add pairs of elements to @sorted. one element will be from the beginning of @list up to its midpoint, and the other will be from the end of @list down to the midpoint. If the number of elements is odd, the pair is added in the order larger, smaller; if not, the order is smaller, larder.

for 0 ..^ $mid -> $i {
    if $odd {
        @sorted.push(@list[@list.end - $i], @list[$i]);
    } else {
        @sorted.push(@list[$i], @list[@list.end - $i]);
    }
}

Now we have a wiggle sorted list. All that remains is to print it in the format the spec suggests.

say q{(}, @sorted.join(q{,}), q{)};

(Full code on Github.)

My code gives the same answer for example 1 as shown there. But for example 2 it gives (1,3,1,3,2,2). I believe this is still correct if we assume the spec really means <= and >= when it mentions < and >. Is this a valid assumption to make? I don't know but I'm going with it.

for reference, here is the Perl version which works the same and has the same flaws.

my @list = sort { $a <=> $b } @ARGV;
my $mid = scalar @list / 2;
my @sorted;
my $odd = scalar @list % 2 == 1;

if ($odd) {
    push @sorted, $list[$mid];
}

for my $i (0 .. $mid - 1) {
    if ($odd) {
        push @sorted, $list[scalar @list - $i - 1], $list[$i];
    } else {
        push @sorted, $list[$i], $list[scalar @list - $i - 1];
    }
}

say q{(}, (join q{,}, @sorted), q{)};

(Full code on Github.)