Perl Weekly Challenge 244: Count Smaller

These are some answers to the Week 244, 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 November 26, 2023 at 23:59). This blog post offers some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 1: Count Smaller

You are given an array of integers.

Write a script to calculate the number of integers smaller than the integer at each index.

Example 1

Input: @int = (8, 1, 2, 2, 3)
Output: (4, 0, 1, 1, 3)

For index = 0, count of elements less than 8 is 4.
For index = 1, count of elements less than 1 is 0.
For index = 2, count of elements less than 2 is 1.
For index = 3, count of elements less than 2 is 1.
For index = 4, count of elements less than 3 is 3.

Example 2

Input: @int = (6, 5, 4, 8)
Output: (2, 1, 0, 3)

Example 3

Input: @int = (2, 2, 2)
Output: (0, 0, 0)

Count Smaller in Raku

It is quite straight forward. First, we sort the input array to reduce the number of comparisons done in the inner loop. I'm not sure whether this is faster, and I don't really care, as the input is so small that it makes little difference anyway. We then loop over the input array, and, for each item, we count the number of items that are less than such said item.

sub count-smaller (@in) {
    my @result;
    my @sorted = @in.sort;
    for @in -> $i {
        my $count = 0;
        for @sorted -> $j {
            last if $j >= $i;
            $count++;
        }
        push @result, $count;
    }
    return @result;
}

for <8 1 2 2 3>, <6 5 4 8>, <2 2 2> -> @test {
    printf "%-12s => ", "@test[]";
    say "" ~ count-smaller @test;
}

This program displays the following output:

$ raku ./count-smaller.raku
8 1 2 2 3    => 4 0 1 1 3
6 5 4 8      => 2 1 0 3
2 2 2        => 0 0 0

Count Smaller in Perl

This is a port to Perl of the above Raku program, and it works exactly the same way.

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

sub count_smaller {
    my @in = @_;
    my @result;
    my @sorted = sort {$a <=> $b } @in;
    for my $i (@in) {
        my $count = 0;
        for my $j (@sorted) {
            last if $j >= $i;
            $count++;
        }
        push @result, $count;
    }
    return @result;
}

for my $test ([<8 1 2 2 3>], [<6 5 4 8>], [<2 2 2>]) {
    printf "%-12s => ", "@$test";
    say join " ", count_smaller @$test;
}

This program displays the following output:

$ perl ./count-smaller.pl
8 1 2 2 3    => 4 0 1 1 3
6 5 4 8      => 2 1 0 3
2 2 2        => 0 0 0

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 December 3, 2023. 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.