Peter’s blog ✴ Week 380 ✴ 29 June 2026

THE WEEKLY CHALLENGE
Frequencies and degrees

The Perl Camel

Task 1

Sum of frequencies

You are given a string consisting of English letters. Write a script to find the vowel and consonant with maximum frequency. Return the sum of the two frequencies.

Examples


Example 1
Input: $str = 'banana'
Output: 5
Vowel: 'a' appears 3 times.
Consonant: 'n' appears 2 times, 'b' appears 1 time.
Max frequency of vowel: 3
Max frequency of consonant: 2

Example 2
Input: $str = 'teestett'
Output: 7
Vowel: 'e' appears 3 times.
Consonant: 't' appears 4 times, 's' appears 1 time.
Max frequency of vowel: 3
Max frequency of consonant: 4

Example 3
Input: $str = 'aeiouuaa'
Output: 3
Vowel: 'a' appears 3 times, 'u' 2 times, 'e', 'i', 'o' 1 time each.
Consonant: None.
Max frequency of vowel: 3
Max frequency of consonant: 0

Example 4
Input: $str = 'rhythm'
Output: 2
Vowel: None
Consonant: 'h' appears 2 times, 'r', 'y', 't', 'm' 1 time each.
Max frequency of vowel: 0
Max frequency of consonant: 2

Example 5
Input: $str = 'x'
Output: 1
Vowel: None
Consonant: 'x' appears 1 time.
Max frequency of vowel: 0
Max frequency of consonant: 1

Analysis

As usual, there are a number of ways of tackling this. Also as usual, I have tried to maximise efficiency and clarity, though in maximising efficiency I may have slightly complicated the code.

My algorithm starts by lower-casing the string and removing anything except [a-z]. The challenge does say 'English letters', which might include upper-case letters, but I decided to treat 'a' and 'A' as being the same letter.

I now make a single pass along the string, accumulating the frequency of letter 'λ' in $freq[ord('λ')], so, for example the number of 'a' in the string is $freq[97] because 'a' is represented by Unicode decimal 97 = hex 61.

It's then just a case of checking the 5 vowel entries and 21 consonant entries in $freq[97 .. 122] to find the maxima, and adding these together for the requested total.

There are two compromises here between efficiency and clarity. The first is that I could have used a hash %freq for accumulating the frequencies, so $freq{'a'} rather than $freq[ord('a')] would be the frequency of 'a' in the string. The reason for choosing the somewhat fussier-looking alternative is that accessing an array element is much faster than a hash value. The other optimisation is that I could have used $freq[0 .. 25] rather than $freq[97 .. 122], accessed using $freq[ord(λ) - ord('a')], but that looks messier and involves an extra subtraction for each letter in $string.

Now these efficiency measures will have a negligible impact on strings of a few 10s or 100s of characters. In real life I would ask the client how long his strings were likely to be, and how many of them needed to be handled every day - and multiply both of his estimates by at least 10 before deciding on ultimate efficiency.

But to check the speed of my algorithm I gave it a string of 10_000_000 random letters and it came up with the answer:

Output: 771589 : vowel 'o' = 385331, consonant 'f' = 386258

in 7 seconds, which I think would be good enough for most real purposes.

Perl Weekly’s review

from PW issue 780

Peter utilising natively fast ASCII byte operations and provides a very elegant and performance-based method to solving weekly challenge. With the help of integer array indices created through the ord() function instead of performing heavier hash lookups, Peter produces an outstandingly fast frequency counter.

Try it 

Your input:



eg: supercalifragilisticexpialidocious

Script


#!/usr/bin/perl

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

use v5.26;    # The Weekly Challenge - 2026-06-29
use utf8;     # Week 380 - task 1 - Sum of frequencies
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';
use Encode;

sum_of_frequencies('abcde');
sum_of_frequencies('');
sum_of_frequencies('banana');
sum_of_frequencies('rhythm');
sum_of_frequencies('aeiouuu');
sum_of_frequencies(
    'Writeascripttofindthevowelandconsonantwithmaximumfrequency' .
    'Returnthesumoftwofrequencies');
    
sub sum_of_frequencies {
    
    my ($string, $j, $k, @freq, $max_v, $max_c);
    
    # initialise
    $string = shift;
    say qq[\nInput:  '$string'];
    $string = lc($string);
    $string =~ s|[^a-z]||g;
    $freq[$_] = 0 for (ord('a') .. ord('z') + 4);
    $max_v = $max_c = '~';
    
    # count frequencies of each letter in $string
    for $j (0 .. length($string) - 1) {
        $freq[ord(substr($string, $j, 1))] ++;
    }
    
    # find maximum frequencies
    for $k ('a', 'e', 'i', 'o', 'u') {
        $max_v = $k if $freq[ord($k)] > $freq[ord($max_v)];
    }
    for $k ('b' .. 'd', 'f' .. 'h', 'j' .. 'n', 'p' .. 't', 
        'v' .. 'z') {  
        $max_c = $k if $freq[ord($k)] > $freq[ord($max_c)];
    }
    
    # report
    say qq[Output: ] . ($freq[ord($max_v)] + $freq[ord($max_c)]) . 
        qq[ : vowel '$max_v' = $freq[ord($max_v)], ] .
        qq[consonant '$max_c' = $freq[ord($max_c)]];
}

18 lines of code

Output from script


Input:  'abcde'
Output: 2 : vowel 'a' = 1, consonant 'b' = 1

Input:  ''
Output: 0 : vowel '~' = 0, consonant '~' = 0

Input:  'banana'
Output: 5 : vowel 'a' = 3, consonant 'n' = 2

Input:  'rhythm'
Output: 2 : vowel '~' = 0, consonant 'h' = 2

Input:  'aeiouuu'
Output: 3 : vowel 'u' = 3, consonant '~' = 0

Input: 
   'WriteascripttofindthevowelandconsonantwithmaximumfrequencyReturnth
   esumoftwofrequencies'
Output: 19 : vowel 'e' = 10, consonant 't' = 9

 

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