Perl Weekly Challenge 258: Sum of Values

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

Spoiler Alert: This weekly challenge deadline is due in a couple of days from now (on March 3, 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: Sum of Values

You are given an array of integers, @int and an integer $k.

Write a script to find the sum of values whose index binary representation has exactly $k number of 1-bit set.

Example 1

Input: @ints = (2, 5, 9, 11, 3), $k = 1
Output: 17

Binary representation of index 0 = 0
Binary representation of index 1 = 1
Binary representation of index 2 = 10
Binary representation of index 3 = 11
Binary representation of index 4 = 100

So the indices 1, 2 and 4 have total one 1-bit sets.
Therefore the sum, $ints[1] + $ints[2] + $ints[4] = 17

Example 2

Input: @ints = (2, 5, 9, 11, 3), $k = 2
Output: 11

Example 3

Input: @ints = (2, 5, 9, 11, 3), $k = 0
Output: 2

Sum of Values in Raku

Although it could easily be done in a one-liner, I've decided to split the solution in two statements, for the sake of clarity. The first statement finds the indexes whose binary representation contains exactly $k "1" (sum of digits equal to $k) and populates the @eligibles array with the corresponding input values in @in. The second statement simply returns the sum oh those values.

sub sum-of-values ($k, @in) {
    my @eligibles = map { @in[$_] }, 
        grep {$_.base(2).comb.sum == $k}, 0..@in.end;
    return @eligibles.sum;
}

my @tests = (1, <2 5 9 11 3>), 
            (2, <2 5 9 11 3>), 
            (0, <2 5 9 11 3>);

for @tests -> @test {
    printf "%-15s => ", "@test[]";
    say sum-of-values @test[0], @test[1];
}

This program displays the following output:

$ raku ./sum-of-values.raku
1 2 5 9 11 3    => 17
2 2 5 9 11 3    => 11
0 2 5 9 11 3    => 2

Sum of Values in Perl

This is a port to Perl of the above Raku program. I counted the number of "1" using the tr/// operator because has no built-in sum function, only to find moments later that I needed to implement a sum subroutine anyway.

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

sub sum {
    my $sum = 0;
    $sum += $_ for @_;
    return $sum;
}

sub sum_of_values {
    my ($k, @in) = @_; 
    my @eligibles = map { $in[$_] } 
        grep {sprintf ("%b", $_) =~ tr/1/1/  == $k} 0..$#in;
    return sum @eligibles;
}

my @tests = ( [1, [<2 5 9 11 3>]], 
              [2, [<2 5 9 11 3>]], 
              [0, [<2 5 9 11 3>]] );

for my $test (@tests) {
    printf "%-3s - %-15s  => ", "$test->[0]", "@{$test->[1]}";
    say sum_of_values $test->[0], @{$test->[1]};
}

This program displays the following output:

$ perl ./sum-of-values.pl
1   - 2 5 9 11 3       => 17
2   - 2 5 9 11 3       => 11
0   - 2 5 9 11 3       => 2

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 March 10, 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.