Perl Weekly Challenge 234: Common Characters

These are some answers to the Week 233, Task 1, of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a couple of days from now (on September 17, 2023 at 23:59). This blog post offers some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 1: Common Characters

You are given an array of words made up of alphabetic characters only.

Write a script to return all alphabetic characters that show up in all words including duplicates.

Example 1

Input: @words = ("java", "javascript", "julia")
Output: ("j", "a")

Example 2

Input: @words = ("bella", "label", "roller")
Output: ("e", "l", "l")

Example 3

Input: @words = ("cool", "lock", "cook")
Output: ("c", "o")

Common Characters in Raku

The common-chars subroutine first transforms the input words into an array of arrays of letters, and then uses the ,infix%E2%88%A9) set intersection operator to find letters common to all sub-arrays.

sub common-chars (@in) {
    my @letters = map { .comb }, @in;
    return ~ ∩ @letters;
}

for <java javascript julia>, <bella label roller>, 
    <cool lock cook> -> @test {
    printf "%-25s => ", "@test[]";
    say common-chars @test;
}

This program displays the following output:

$ raku ./common-chars.raku
java javascript julia     => [a j]
bella label roller        => [l e]
cool lock cook            => [c o]

Common Characters in Perl

This is essentially a port to Perl of the above Raku program, except that, since Perl doesn't have a set intersection operator, we use the %histo hash to store the letter frequencies, and extract from the histogram letters whose frequency is equal to the input word count.

use strict;
use warnings;
use feature 'say';

sub common_chars {
    my $count = scalar @_;
    my @letters = map { [ split // ] } @_;
    my %histo;       # letter histogram
    for my $w_ref (@letters) {
        my %unique = map { $_ => 1 } @$w_ref;
        $histo{$_}++ for keys %unique;
    }
    my @result = grep { $histo{$_} == $count } keys %histo;
    return "@result";
}

for my $test ([<java javascript julia>], 
    [<bella label roller>], [<cool lock cook>]) {
    printf "%-25s => ", "@$test";
    say common_chars @$test;
}

This program displays the following output:

$ perl ./common-chars.pl
java javascript julia     => a j
bella label roller        => e l
cool lock cook            => o c

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on September 24, 2023. And, please, also spread the word about the Perl Weekly Challenge if you can.

Leave a comment

About laurent_r

user-pic I am the author of the "Think Perl 6" book (O'Reilly, 2017) and I blog about the Perl 5 and Raku programming languages.