Peter
Peter Campbell Smith

Uniquely ranked

Weekly challenge 260 — 11 March 2024

Week 260 - 11 Mar 2024

Task 1

Task — 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.

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];
}   

Output


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)