Peter
Peter Campbell Smith

Frequent number
and shortest word

Weekly challenge 265 — 15 April 2024

Week 265 - 15 Apr 2024

Task 1

Task — 33% appearance

You are given an array of integers, @ints. Write a script to find an integer in the given array that appears 33% or more. If more than one is found, return the smallest. If none is found then return undef.

Examples


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

1 appeared 1 times.
2 appeared 2 times.
3 appeared 4 times.

3 appeared 50% (>33%) in the given array.

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

1 appeared 2 times.

1 appeared 100% (>33%) in the given array.

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

1 appeared 1 times.
2 appeared 1 times.
3 appeared 1 times.

Since all three appeared 33.3% (>33%) in the given array.
We pick the smallest of all.

Analysis

This is a task where I think the obvious method is the best.

First we count the frequencies of all the numbers in @times.

Then we look for the first $times[$i] which is greater than 33% of the size of @ints.

If none meets that criterion we return undef.

Try it 

Try running the script with any input:



example: 1, 2, 3, 4, 5, 5, 5

Script


#!/usr/bin/perl

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

use v5.26;    # The Weekly Challenge - 2024-04-15
use utf8;     # Week 265 - task 1 - 33% appearance
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';

my ($j, @ints);

over_33perct_appearance(1, 2, 3, 3, 3, 3, 4, 2);
over_33perct_appearance(1, 1);
over_33perct_appearance(1, 2, 3);
over_33perct_appearance(1, 2, 3, 4);
over_33perct_appearance(8, 8, 8, 9, 9, 9, 7, 7, 7);

for $j (1 .. 100) {
    push @ints, int(rand(3)) + 1;
}
over_33perct_appearance(@ints);

sub over_33perct_appearance {
    
    my (@ints, @times, $one_third, $i);
    
    # intialise
    @ints = @_;
    say qq[\nInput:  \@ints = (] . join(', ', @ints) . ')';
    $one_third = (scalar @ints) * 0.33;
    
    # count frequenceies
    $times[$_] ++ for @ints;
    
    # find smallest with >33%
    for ($i = 0; $i < @times; $i ++) {
        next unless defined $times[$i];
        if ($times[$i] > $one_third) {
            say qq[Output: $i (] . int($times[$i] / @ints * 100) . '%)';
            return;
        }
    }
    
    # none found
    say qq[Output: undef];
}

Output


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

Input:  @ints = (1, 1)
Output: 1 (100%)

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

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

Input:  @ints = (8, 8, 8, 9, 9, 9, 7, 7, 7)
Output: 7 (33%)

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