Perl Weekly Challenge 263: Merge Items

These are some answers to the Week 263, 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 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 2: Merge Items

You are given two 2-D array of positive integers, $items1 and $items2 where element is pair of (item_id, item_quantity).

Write a script to return the merged items.

Example 1

Input: $items1 = [ [1,1], [2,1], [3,2] ]
       $items2 = [ [2,2], [1,3] ]
Output: [ [1,4], [2,3], [3,2] ]

Item id (1) appears 2 times: [1,1] and [1,3]. Merged item now (1,4)
Item id (2) appears 2 times: [2,1] and [2,2]. Merged item now (2,3)
Item id (3) appears 1 time: [3,2]

Example 2

Input: $items1 = [ [1,2], [2,3], [1,3], [3,2] ]
       $items2 = [ [3,1], [1,3] ]
Output: [ [1,8], [2,3], [3,3] ]

Example 3

Input: $items1 = [ [1,1], [2,2], [3,3] ]
       $items2 = [ [2,3], [2,4] ]
Output: [ [1,1], [2,9], [3,3] ]

Merge Items in Raku

We iterate over the items of the two arrays and store in a hash (%total) the quantities. At the end, we reorganize the hash into two 2-D arrays of positive integers (to retrieve the input data format).

sub merge-items (@in1, @in2) {
    my %total;
    for (|@in1, |@in2) -> @items {
        %total{@items[0]} += @items[1];
    }
    return map { ($_, %total{$_} ) }, %total.keys.sort;
}

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

This program displays the following output:

$ raku ./merge-items.raku
1 1 2 1 3 2     - 2 2 1 3    => ((1 4) (2 3) (3 2))
1 2 2 3 1 3 3 2 - 3 1 1 3    => ((1 8) (2 3) (3 3))
1 1 2 2 3 3     - 2 3 2 4    => ((1 1) (2 9) (3 3))

Merge Items in Perl

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

sub merge_items {
    my %total;
    for my $in (@_) {
        for my $items (@$in) {
            $total{$items->[0]} += $items->[1];
        }
    }
    return map { "[ $_  $total{$_} ] " } sort keys %total;
}

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

Note that, when printing the input test data, the program displays only the first item (the first pair) of each test.

This program displays the following output:

$ perl ./merge-items.pl
[1  1] ... => [ 1  4 ] [ 2  3 ] [ 3  2 ]
[1  2] ... => [ 1  8 ] [ 2  3 ] [ 3  3 ]
[1  1] ... => [ 1  1 ] [ 2  9 ] [ 3  3 ]

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.