Perl Weekly Challenge 264: Target Array

These are some answers to the Week 264, Task 2, of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few days from now (on April 14, 2024 at 23:59). This blog post provides some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 2: Target Array

You are given two arrays of integers, @source and @indices. The @indices can only contains integers 0 <= i < size of @source.

Write a script to create target array by insert at index $indices[i] the value $source[i].

Example 1

Input: @source  = (0, 1, 2, 3, 4)
       @indices = (0, 1, 2, 2, 1)
Output: (0, 4, 1, 3, 2)

@source  @indices  @target
0        0         (0)
1        1         (0, 1)
2        2         (0, 1, 2)
3        2         (0, 1, 3, 2)
4        1         (0, 4, 1, 3, 2)

Example 2

Input: @source  = (1, 2, 3, 4, 0)
       @indices = (0, 1, 2, 3, 0)
Output: (0, 1, 2, 3, 4)

@source  @indices  @target
1        0         (1)
2        1         (1, 2)
3        2         (1, 2, 3)
4        3         (1, 2, 3, 4)
0        0         (0, 1, 2, 3, 4)

Example 3

Input: @source  = (1)
       @indices = (0)
Output: (1)

The way the target array is constructed (as detailed in the examples) is somewhat weird, so that we cannot use array slices as I was originally hoping. We have to build the target array iteratively, item by item.

Also note that we are not told what to do if the @source and @indices arrays don't have the same size, so we will assume they have the same size.

Target Array in Raku

In order to built the target array in accordance with the rules explained in the examples, the easiest is to use the splice routine, which can add, remove or replace elements of an array. In this specific case, we don't remove or replace items of the array (this is why the third parameter of the splice function call is set to 0), but just add one value at a time.

sub target-array (@source, @indices) {
    my @target;
    for 0..@source.end -> $i {
        splice @target, @indices[$i], 0,  @source[$i];
    }
    return @target;
}

my @tests = ( (0, 1, 2, 3, 4), (0, 1, 2, 2, 1) ),
            ( (1, 2, 3, 4, 0), (0, 1, 2, 3, 0) ),
            ( (1,), (0,) );
for @tests -> @test {
    printf "%-10s - %-10s => ", "@test[0]", "@test[1]";
    say target-array @test[0], @test[1];
}

This program displays the following output:

$ raku ./target-array.raku
0 1 2 3 4  - 0 1 2 2 1  => [0 4 1 3 2]
1 2 3 4 0  - 0 1 2 3 0  => [0 1 2 3 4]
1          - 0          => [1]

Target Array in Perl

This is a port to Perl of the above Raku program. For our practical purpose, Perl's splice function behaves essentially the same way as Raku's splice routine.

use strict;
use warnings;
use feature 'say';

sub target_array  {
    my @source = @{$_[0]};
    my @indices = @{$_[1]};
    my @target;
    for my $i (0..$#source) {
        splice @target, $indices[$i], 0,  $source[$i];
    }
    return @target;
}

my @tests = ( [ [0, 1, 2, 3, 4], [0, 1, 2, 2, 1] ],
              [ [1, 2, 3, 4, 0], [0, 1, 2, 3, 0] ],
              [ [1,], [0,] ] );
for my $test (@tests) {
    printf "%-10s - %-10s => ", "@{$test->[0]}", "@{$test->[1]}";
    say join " ", target_array $test->[0], $test->[1];
}

This program displays the following output:

$ perl ./target-array.pl
0 1 2 3 4  - 0 1 2 2 1  => 0 4 1 3 2
1 2 3 4 0  - 0 1 2 3 0  => 0 1 2 3 4
1          - 0          => 1

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on April 21, 2024. And, please, also spread the word about the Perl Weekly Challenge if you can.

Leave a comment

About laurent_r

user-pic I am the author of the "Think Perl 6" book (O'Reilly, 2017) and I blog about the Perl 5 and Raku programming languages.