Peter’s blog ✴ Week 359 ✴ 2 February 2026

THE WEEKLY CHALLENGE
Persistent reduction

The Perl Camel

Task 2

String reduction

You are given a word containing only alphabetic characters.

Write a function that repeatedly removes adjacent duplicate characters from the word until no adjacent duplicates remain and return the final word.

Examples


Example 1
Input: $word = 'aabbccdd'
Output: ''
Iteration 1: remove 'aa', 'bb', 'cc', 'dd' => ''

Example 2
Input: $word = 'abccba'
Output: ''
Iteration 1: remove 'cc' => 'abba'
Iteration 2: remove 'bb' => 'aa'
Iteration 3: remove 'aa' => ''

Example 3
Input: $word = 'abcdef'
Output: 'abcdef'
No duplicate found.

Example 4
Input: $word = 'aabbaeaccdd'
Output: 'aea'
Iteration 1: remove 'aa', 'bb', 'cc', 'dd' => 'aea'

Example 5
Input: $word = 'mississippi'
Output: 'm'
Iteration 1: Remove 'ss', 'ss', 'pp' => 'miiii'
Iteration 2: Remove 'ii', 'ii' => 'm'

Analysis

My solution is this:

$count = $string =~ s|(\w)\1||g while $count;

with $count initialised to 1.

It works, it's short, it's efficient but it probably fails my usual test of 'is it understandable by a non-Perl maintainer'?

It works because $string =~ s|(\w)\1||g eliminates all adjacent pairs of letters in the initial $string. But it only makes one pass, so, for example 'abba' will only be reduced to 'aa'.

It does however return (in scalar context) a $count of its deletions and if that isn't zero the while ensures that it tries again until no further pairs exist.

I am aware that it's possible to do that within the regex, but I think that makes it even more opaque.

I used \w rather than [a-z] to allow for non-Latin alphabets such as Greek or Cyrillic, and I also used lc() in the initialisation so that 'Ee' would be deleted, which might - or might not - be what Mohammad wanted.

Perl Weekly’s review

from PW issue 759

This approach is a good example of intentional design and practical implementation. The approach to handling very large integer strings uses the digital root function; the string reduction uses a simple loop. Peter also considers edge cases, such as case insensitivity and non-Latin alphabets, which will improve the overall usability and applicability in the real world.

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

Try it 

Try running the script with any input:



example: RewardDrawer

Script


#!/usr/bin/perl

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

use v5.26;    # The Weekly Challenge - 2026-02-02
use utf8;     # Week 359 - task 2 - String reduction
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';
use Encode;

string_reduction('mississippi');
string_reduction('house');
string_reduction('abcdefggfedcba');
string_reduction('aaaaaaaaaaaaaaaaaa');
string_reduction('abcdeEDCBA');
string_reduction('αβγδεεδγβαω');

sub string_reduction {
    
    my ($string, $count);
    
    # initialise
    $string = lc($_[0]);
    $count = 1;
    
    # delete matched pairs
    $count = $string =~ s|(\w)\1||g while $count;
    
    say qq[\nInput:  '$_[0]'];
    say qq[Output: '$string'];
}

7 lines of code

Output from script


Input:  'mississippi'
Output: 'm'

Input:  'house'
Output: 'house'

Input:  'abcdefggfedcba'
Output: ''

Input:  'aaaaaaaaaaaaaaaaaa'
Output: ''

Input:  'abcdeEDCBA'
Output: ''

Input:  'αβγδεεδγβαω'
Output: 'ω'

 

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