Peter’s blog ✴ Week 260 ✴ 11 March 2024

THE WEEKLY CHALLENGE
Uniquely ranked

The Perl Camel

Task 1

Unique occurrences

You are given an array of integers, @ints. Write a script to return 1 if the number of occurrences of each value in the given array is unique or 0 otherwise.

Examples


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

The number 1 occurred 3 times.
The number 2 occurred 2 times.
The number 3 occurred 1 time.

All occurrences are unique, therefore the output is 1.

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

Example 3
Input: @ints = (-2,0,1,-2,1,1,0,1,-2,9)
Output: 1

Analysis

I approached this in what seemed to me to be the obvious way. First, I count the number of times each $value appears in @ints and store that in $occurs{$value}. I use a hash because $value might be negative.

Then I do another loop over keys %occurs and check if $seen{$occurs{$value}} is defined. If it isn't, then I haven't seen this frequency before and I set $seen{$occurs{$value}} = $value for future reference.

If it is defined then this is a duplicate value, so I set $output to 0 and record the reason for failure - which is that $value and $seen{$occurs{$value}} both occur $occurs{$value} times.

I tried this with 10 000 random numbers and it completes in milliseconds, so I don't think it's worth looking to optimise it.

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, 2, 3, 3, 3, 4

Script


#!/usr/bin/perl

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

use v5.26;    # The Weekly Challenge - 2024-03-11
use utf8;     # Week 260 - task 1 - Unique occurrences
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';

unique_occurrences(1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5);
unique_occurrences(1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5);
unique_occurrences(1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5);

my (@ints, $j);
for $j (0 .. 99) {
    $ints[$j] = int(rand(21) - 10);
}
unique_occurrences(@ints);

sub unique_occurrences {
    
    my (@ints, %occurs, $output, $reason, $value, %seen);
    
    # initialise
    @ints = @_;
    $output = 1;
    $reason = '';
    say qq[\nInput: \@ints = (] . join(', ', @ints) . ')';
    
    # count occurrences
    $occurs{$_} ++ for @ints;
    
    # see if they are all 1
    for $value (keys %occurs) {
        if (defined $seen{$occurs{$value}}) {
            $output = 0;
            $reason = qq[($value and $seen{$occurs{$value}} both occur $occurs{$value} times)];
            last;
        }           
        $seen{$occurs{$value}} = $value;
    }
    
    # show the answer
    say qq[Output: $output $reason];
}   

14 lines of code

Output from script


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

Input: @ints = (1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5)
Output: 0 (5 and 4 both occur 5 times)

Input: @ints = (1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5)
Output: 0 (4 and 3 both occur 3 times)

Input: @ints = (1, 2, 9, 1, 0, 4, -1, -6, -4, -7, -8, -6, -5, 10, 10, 10, 5, 4, 4, 1, -8, -6, -3, 2, 8, 4, 2, 6, 7, 3, 4, 7, -8, 8, -9, 1, -7, 4, 1, -2, 7, -1, -7, 6, 0, -4, 4, 0, 10, 4, 6, -5, 9, -1, 3, -2, -4, 8, 6, -9, 0, -8, -1, 5, 3, 1, 1, 0, 3, 6, -5, -7, -4, 1, -1, 5, 3, -6, -4, -6, 0, -3, 7, 4, -7, 8, 9, 10, -4, 9, -4, -6, 2, -9, -9, 10, -2, -1, -8, 8)
Output: 0 (-9 and 9 both occur 4 times)
	

 

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