Peter’s blog ✴ Week 242 ✴ 6 November 2023

THE WEEKLY CHALLENGE
Flipping members

The Perl Camel

Task 1

Missing members

You are given two arrays of integers. Write a script to list the members of each array which are missing from the other array.

Examples


Example 1
Input: @arr1 = (1, 2, 3)
       @arr2 = (2, 4, 6)
Output: ([1, 3], [4, 6])

(1, 2, 3) has 2 members (1, 3) missing in the array (2, 4, 6).
(2, 4, 6) has 2 members (4, 6) missing in the array (1, 2, 3).

Example 2
Input: @arr1 = (1, 2, 3, 3)
       @arr2 = (1, 1, 2, 2)
Output: ([3])

(1, 2, 3, 3) has 2 members (3, 3) missing in the array (1, 1, 2, 2). Since they are same, keep just one.
(1, 1, 2, 2) has 0 member missing in the array (1, 2, 3, 3).

Analysis

This is easily stated and fairly easily solved, but it is harder to come up with a good solution that would work efficiently if the arrays had, thousands of members. In such a case I can think of two approaches:

1 Sort each array and work steadily along both of them in parallel, noting where a value was missinng from either.

2 Use a hash and build $exists{$j} for every $j in @arr2, and then match @arr1 sequentially aginst the hash.

But our arrays are small and I didn't use either of those approaches. Mine simply does this:

for $j (@two) {
  @one = grep { $_ != $j } @one;
}

This iterates $j over the members of @two and creates a new @one which omits any $two[$j]. For this to give the required answer, the arrays have to be made unique, and I used the handy module List::Uniq for that.

And, of course, all of these solutions need to be done again with @arr1 and @arr2 swapped.

I am sorry that the 'Try it' feature is currently working very slowly or not at all owing to some issue with my web hosting provider.

Try it 

Try running the script with any input:



example: 1, 2, 3, 4, 5



example: 3, 4, 5, 6, 7

Script


#!/usr/bin/perl

use v5.16;    # The Weekly Challenge - 2023-11-06
use utf8;     # Week 242 task 1 - Missing members
use strict;   # Peter Campbell Smith
use warnings; # Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge

use List::Uniq 'uniq';

missing_members([1, 2, 3], [2, 4, 6]);
missing_members([1, 2, 3, 3], [1, 1, 2, 2]);
missing_members([1, 2, 3, 4, 5, 6, 7, 8, 9], [2, 4, 6, 8, 10]);

# make bigger example
my ($j, @arr1, @arr2);
for $j (0 .. 29) {
    push @arr1, int(rand(15) + 1);
    push @arr2, int(rand(15) + 1);
}
missing_members(\@arr1, \@arr2);

sub missing_members {
    
    printf('%sInput:  ([%s], [%s])%s', "\n", join(', ', @{$_[0]}), join(', ', @{$_[1]}), "\n");
    printf('Output: ([%s], [%s])%s', mm($_[0], $_[1]), mm($_[1], $_[0]), "\n");
}

sub mm {
    
    my (@one, @two, $j);
    
    # make each array unique
    @one = uniq(@{$_[0]});
    @two = uniq(@{$_[1]});
    
    # delete from @one anything that occurs in @two
    for $j (@two) {
        @one = grep { $_ != $j } @one;
    }
    
    # and return what's left
    return join(', ', @one);
}
    

10 lines of code

Output from script


Input:  ([1, 2, 3], [2, 4, 6])
Output: ([1, 3], [4, 6])

Input:  ([1, 2, 3, 3], [1, 1, 2, 2])
Output: ([3], [])

Input:  ([1, 2, 3, 4, 5, 6, 7, 8, 9], [2, 4, 6, 8, 10])
Output: ([1, 3, 5, 7, 9], [10])

Input:  ([13, 7, 6, 9, 7, 8, 11, 1, 14, 7, 15, 12, 11, 7, 5, 4, 1, 7, 11, 5, 14, 3, 8, 8, 6, 3, 15, 9, 12, 11], 
         [7, 5, 12, 10, 1, 5, 9, 12, 7, 9, 8, 3, 14, 14, 10, 15, 10, 10, 6, 7, 10, 15, 1, 8, 8, 14, 15, 1, 2, 11])
Output: ([13, 4], [10, 2])


 

Any content of this website which has been created by Peter Campbell Smith is in the public domain