Peter
Peter Campbell Smith

Unique arrays and
differing dates

Weekly challenge 183 — 19 September 2022

Week 183 - 19 Sep 2022

Task 1

Task — Unique array

You are given list of arrayrefs. Write a script to remove the duplicate arrayrefs from the given list.

Examples


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

Example 2
Input: @list = ([9,1], [3,7], [2,5], [2,5])
Output: ([9, 1], [3,7], [2,5])

Analysis

We are given list of arrayrefs and asked to write a script to remove duplicates, ie to eliminate references to arrays which are identical to earlier ones. The examples show the arrays containing positive integers; I have generalised the problem to assume that the array elements can be uniquely represented as strings. This allows any type of number or character string or null, but not perhaps references.

So I wrote a sub signature(@a) which creates a string by concatenating the array elements with a suitable separator. I used 0xFF as the separator, which will not occur in the representation of any array elements described above.

It's then just a matter of going through the supplied list, checking that $seen{$signature} is null and if so adding the current list item to the output list and setting $seen{$signature} = 1.

There is some ambiguity in the task description, and, for example, my algorithm will treat all of the following as being identical: [1, 2], [1.0, 2.0], [1e0, 2e0], ['1', '2'].

Try it 

Try running the script with any input:



example: [1,2], [3,4], [5,6], [1,2]

Script


#!/usr/bin/perl

# Peter Campbell Smith - 2022-09-20
# PWC 183 task 1

use v5.28;
use utf8;
use warnings;

my (@lists, @list, $separator, $list_ref, $item, $signature, @new_list, %seen);

# inputs
@lists = (
    [[1,2], [3,4], [5,6], [1,2]], 
    [[9,1], [3,7], [2,5], [2,5]],
    [[4,6], [6,4], [9,0], [6,4], [5,7], [7,-1], [4,6]],
    [['cat', 'dog'], ['cat', 'mouse'], ['cat, cat'], ['dog', 'cat'], ['mouse', 'mouse'], ['cat', 'mouse']],
    [[1, 2], [1.0, 2.0], [1e0, 2e0], ['1', '2'], [4 - 3, 9 - 8], [0, 0]]);

# loop over inputs and initialise
$separator = 0xFF;
while ($list_ref = shift @lists) {
    @list = @$list_ref;
    @new_list = ();
    %seen = ();
    say '';
    
    # loop over items in @list and add them to @new_list if unseen so far
    for $item (@list) {
        $signature = array_signature($item);
        next if $seen{$signature};
        push @new_list, $item;
        $seen{$signature} = 1;
    }

    # show the input and output
    show_list('Input: ', @list);
    show_list('Output:', @new_list);
}

sub array_signature {
    
    # returns a stringified copy of inpout @list
    my ($list, $j, $signature);
    
    $list = shift;
    for $j (0 .. scalar @$list - 1) {
        $signature .= $list->[$j] . $separator;
    }
    return $signature;
}

sub show_list {
    
    # displays @list in Mohammad's format
    my ($caption, @list, $output, $j);
    
    ($caption, @list) = @_;
    $output = qq[$caption (];
    for $item (@list) {
        $output .= '[';
        for $j (0 .. scalar @$item - 1) {
            $output .= $item->[$j] . ', '
        }
        $output =~ s|, $|], |;
    }
    $output =~ s|, $|)|;
    say $output;
}
    

Output


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

Input:  ([9, 1], [3, 7], [2, 5], [2, 5])
Output: ([9, 1], [3, 7], [2, 5])

Input:  ([4, 6], [6, 4], [9, 0], [6, 4], [5, 7], [7, -1], [4, 6])
Output: ([4, 6], [6, 4], [9, 0], [5, 7], [7, -1])

Input:  ([cat, dog], [cat, mouse], [cat, cat], [dog, cat], [mouse, mouse], [cat, mouse])
Output: ([cat, dog], [cat, mouse], [cat, cat], [dog, cat], [mouse, mouse])

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