Perl Weekly Challenge 228: Unique Sum

These are some answers to the Week 228, 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 August 6, 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: Unique Sum

You are given an array of integers.

Write a script to find out the sum of unique elements in the given array.

Example 1

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

In the given array we have 2 unique elements (1, 3).

Example 2

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

In the given array no unique element found.

Example 3

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

In the given array every element is unique.

Many programming languages, including Raku, have a built-in unique function or method that return a list of distinct values of an input list, and the List::Util core Perl module also offers several functions doing that. But they cannot be used here, because these functions keep one sample of each value from the input, and that's not what is desired here. In this task, we want to keep only the values that appear once in the input (and discard entirely any values that appear more than once).

Unique Sum in Raku

The unique-sum subroutine in the program below transforms the input list into a Bag, i.e. essentially an histogram of the values, a data structure that keeps track of the number of occurrences of each value. From there, it derives an array (@unique) containing all the items that appear only once. And, finally, it returns ther sum of these values.

sub unique-sum (@in) {
    my $histo = @in.Bag;    # histogram
    my @unique = grep { $histo{$_} == 1 }, $histo.keys;
    return [+] @unique;
}

for (2, 1, 3, 2), (1, 1, 1, 1), (2, 1, 3, 4) -> @test {
    printf "%-10s => ", "@test[]";
    say unique-sum @test;
}

This program displays the following output:

$ raku ./unique-sum.raku
2 1 3 2    => 4
1 1 1 1    => 0
2 1 3 4    => 10

Unique Sum in Perl

Perl doesn't have Bags, but we can use a hash to the same effect. The %histo hash tracks the number of occurrences of each item, and the @unique array keeps the items that appear only once. The unique_sum subroutine finally computes the sum of these items.

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

sub unique_sum {
    my %histo;      # histogram
    $histo{$_}++ for @_;
    my @unique = grep { $histo{$_} == 1 } keys %histo;
    my $sum = 0;
    $sum += $_ for @unique;
    return $sum;
}

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

This program displays the following output:

$ perl ./unique-sum.pl
2 1 3 2    => 4
1 1 1 1    => 0
2 1 3 4    => 10

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 August 13, 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.