Peter
Peter Campbell Smith

Occurrences

Weekly challenge 283 — 19 August 2024

Week 283: 19 Aug 2024

Task 1

Task — Unique number

You are given an array of integers, @ints, where every element appears more than once except one element. Write a script to find the one element that appears exactly one time.

Examples


Example 1
Input: @ints = (3, 3, 1)
Output: 1

Example 2
Input: @ints = (3, 2, 4, 2, 4)
Output: 3

Example 3
Input: @ints = (1)
Output: 1

Example 4
Input: @ints = (4, 3, 1, 1, 1, 4)
Output: 3

Analysis

My first idea for solving this was to concatenate the members of @ints into $string, enclosing each element with some sort of brackets. I tried it with <> as those characters are not special in a regular expression. So:

1, 2, 2, 3, 3 => <1><2><2><3><3>

I can then do this:

for $i (@ints) {
	if (@string !~ m|<$i>.*<$i>|) {
		... $i is the answer

That works for the given examples, and indeed for any example I could think of. But it is slightly inefficient in that it will check the duplicated numbers more than once if they appear more than once before the unique one.

So I went for a 'purer' solution, which is simply to count the frequency $freq{$i} of all the numbers $i, and then to loop through %freq to find the first $freq{$i} having a value of 1.

Neither of these solutions tests the validity of the assertion that there is one and only one element of @ints that occurs just once, and in a production environment it would of course be very advisable to do that.

Try it 

Try running the script with any input:



example: 2, 3, 7, 3, 9, 8, 2, 8, 9

Script


#!/usr/bin/perl

# Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge

use v5.26;    # The Weekly Challenge - 2024-08-19
use utf8;     # Week 283 - task 1 - Unique number
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';

unique_number(1, 1, 2, 3, 4, 5, 3, 4, 5);
unique_number(3, 2, 4, 2, 4);
unique_number(7);
unique_number(4, 3, 1, 1, 4);
unique_number(123, 456, 77, 9999, 55, 55, 9999, 77, 456);

sub unique_number {
    
    my (@ints, %freq, $j);
    
    @ints = @_;
    say qq[\nInput:  \@ints = (] . join(', ', @ints) . ')';
    
    # count occurrences of each number
    $freq{$_} ++ for @ints;
    
    # find the (first) one that only occurs once
    for $j (keys %freq) {
        if ($freq{$j} == 1) {
            say qq[Output: $j];
            return;
        }
    }
    
    # none occurs once
    say qq[Output: none];
}

Output


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

Input:  @ints = (3, 2, 4, 2, 4)
Output: 3

Input:  @ints = (7)
Output: 7

Input:  @ints = (4, 3, 1, 1, 4)
Output: 3

Input:  @ints = (123, 456, 77, 9999, 55, 55, 9999, 77, 
   456)
Output: 123

 

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