Peter’s blog ✴ Week 335 ✴ 18 August 2025

THE WEEKLY CHALLENGE
Common winner

The Perl Camel

Task 1

Common characters

You are given an array of words. Write a script to return all the characters that are in every word in the given array, including duplicates.

Examples


Example 1
Input: @words = ('bella', 'label', 'roller')
Output: ('e', 'l', 'l')

Example 2
Input: @words = ('cool', 'lock', 'cook')
Output: ('c', 'o')

Example 3
Input: @words = ('hello', 'world', 'pole')
Output: ('l', 'o')

Example 4
Input: @words = ('abc', 'def', 'ghi')
Output: ()

Example 5
Input: @words = ('aab', 'aac', 'aaa')
Output: ('a', 'a')

Analysis

As always, there are various ways to do this, and here is mine.

I create a data structure:

$count->{$c}->[$w] = $n

where $c is a character which occurs in one of the input words, $w is the (zero-based) index of a word in the input, and $n is the number of instances of $c in $word[$n]. So using Mohammad's first example $count->{'l'}->{1} == 2 because the letter l occures twice in word 1, ie in 'label'.

Then for every $c - ie for every letter that occurs in at least one word - I loop over $w to find the least $n. So for Mohammad's second example - 'cool', 'lock', 'cook' - I will find that o occurs least frequently - ie once - in 'lock'. I therefore add 'o', once to my output string. Had it occurred (at least) twice in every word I would have added it twice, and so on.

And that's it, save for a minor wrinkle, which is that if $c doesn't occur in word $w, for example, there is no r in bella, then $count->{$c}->[$w] is undefined. That's OK because in a numeric context Perl regards undefined to mean zero, but it does output a warning. So to suppress those I have included no warnings 'uninitialized' in my code, which is potentially unwise, but I judge it to be acceptable here.

Perl Weekly’s review

from PW issue 735

Solutions demonstrate strong problem-solving skills with particular excellence in the binary representation approach for Task 2, which is both computationally optimal and elegantly implemented.

This review may cover either or both challenges for this week.

Try it 

Try running the script with any input:



example: paragon, marathon, banana

Script


#!/usr/bin/perl

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

use v5.26;    # The Weekly Challenge - 2025-08-18
use utf8;     # Week 335 - task 1 - Common characters
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';

common_characters('bella', 'label', 'roller');
common_characters('cool', 'lock', 'cook');
common_characters('hello', 'world', 'pole');
common_characters('abc', 'def', 'ghi');
common_characters('aab', 'aac', 'aaa');

sub common_characters {
    
    my (@words, @chars, $count, $c, $min, $output, $w, $k);
    
    no warnings 'uninitialized';
    @words = @_;
    
    # create count of character $c in word $w
    for $w (0 .. $#words) {
        @chars = split('', $words[$w]);
        $count->{$chars[$_]}->[$w] ++ for 0 .. $#chars;
    }
    
    # loop $c over characters
    for $c (sort keys %$count) {
        
        # find minimum number of occurrences of $c in all words  
        $min = 1e6;
        for $w (0 .. $#words) {
            $k = $count->{$c}->[$w];
            $min = $k if $k < $min;
        }
        
        # output that number of occurrences of $c
        $output .= qq['$c', ] for 1 .. $min;
    }
    
    # report
    say qq[\nInput:  ('] . join(q[', '], @words) . q[')];
    say qq[Output: (] . substr($output, 0, -2) . ')';
}

15 lines of code

Output from script


Input:  ('bella', 'label', 'roller')
Output: ('e', 'l', 'l')

Input:  ('cool', 'lock', 'cook')
Output: ('c', 'o')

Input:  ('hello', 'world', 'pole')
Output: ('l', 'o')

Input:  ('abc', 'def', 'ghi')
Output: ()

Input:  ('aab', 'aac', 'aaa')
Output: ('a', 'a')

 

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