Perl Weekly Challenge 263: Target Index

These are some answers to the Week 263, Task 1, 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 7, 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 1: Target Index

You are given an array of integers, @ints and a target element $k.

Write a script to return the list of indices in the sorted array where the element is same as the given target element.

Example 1

Input: @ints = (1, 5, 3, 2, 4, 2), $k = 2
Output: (1, 2)

Sorted array: (1, 2, 2, 3, 4, 5)
Target indices: (1, 2) as $ints[1] = 2 and $k[2] = 2

Example 2

Input: @ints = (1, 2, 4, 3, 5), $k = 6
Output: ()

No element in the given array matching the given target.

Example 3

Input: @ints = (5, 3, 2, 4, 2, 1), $k = 4
Output: (4)

Sorted array: (1, 2, 2, 3, 4, 5)
Target index: (4) as $ints[4] = 4

In theory, it is not necessary to sort the input array. We could simply count the number of items that are less than the target value and those which are equal to the target value. This is algorithmically simpler and probably faster (at least for large arrays). However, with the small input arrays of the examples, there is no need for performance optimization. So we will use the built-in sort functions of Perl and Raku.

Target Index in Raku

We simply use the sort method to sort the input array and the grep routine as a filter to select the subscripts in the sorted array for which the values are equal to the target.

sub find-index ($target, @in) {
    my @sorted = @in.sort;
    my @out = grep {@sorted[$_] == $target}, 0..@sorted.end;
    return @out;
}

my @tests = (2, (1, 5, 3, 2, 4, 2)), 
            (6, (1, 2, 4, 3, 5)), 
            (4, (5, 3, 2, 4, 2, 1));
for @tests -> @test {
    printf "%d - %-15s => ", @test[0], "@test[1]";
    say find-index @test[0], @test[1];
}

This program displays the following output:

$ raku ./find-index.raku
2 - 1 5 3 2 4 2     => [1 2]
6 - 1 2 4 3 5       => []
4 - 5 3 2 4 2 1     => [4]

Target Index in Perl

This is a port to Perl of the above Raku program.

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

sub find_index {
    my $target = shift;
    my @sorted = sort { $a <=> $b } @_;
    my @out = grep {$sorted[$_] == $target} 0..$#sorted;
    return "@out" || "()";
}

my @tests = ( [2, [1, 5, 3, 2, 4, 2]], 
              [6, [1, 2, 4, 3, 5]], 
              [4, [5, 3, 2, 4, 2, 1]] );
for my $test (@tests) {
    printf "%d - %-15s => ", $test->[0], "@{$test->[1]}";
    say find_index  @$test[0], @{$test->[1]};
}

This program displays the following output:

$ perl ./find-index.pl
2 - 1 5 3 2 4 2     => 1 2
6 - 1 2 4 3 5       => ()
4 - 5 3 2 4 2 1     => 4

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 14, 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.