Peter’s blog ✴ Week 345 ✴ 27 October 2025

THE WEEKLY CHALLENGE
Peak at the answers

The Perl Camel

Task 2

Last visitor

You are given an integer array @ints where each element is either a positive integer or -1.

Process the array from left to right while maintaining two lists:
@seen stores previously seen positive integers (newest at the front)
@ans stores the answers for each -1

Rules:
If $ints[$i] is a positive number insert it at the front of @seen
If $ints[$i] is -1:
... Let $x be how many -1s in a row we’ve seen before this one.
... If $x < length(@seen) append $seen[$x] to @ans
... Else append -1 to @ans

At the end, return @ans.

Examples


Example 1
Input: @ints = (5, -1, -1)
Output: (5, -1)
@seen = (5)
First  -1: @ans = (5)
Second -1: @ans = (5, -1)

Example 2
Input: @ints = (3, 7, -1, -1, -1)
Output: (7, 3, -1)
@seen = (3, 7)
First  -1: @ans = (7)
Second -1: @ans = (7, 3)
Third  -1: @ans = (7, 3, -1)

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

Example 4
Input: @ints = (10, 20, -1, 30, -1, -1)
Output: (20, 30, 20)

Example 5
Input: @ints = (-1, -1, 5, -1)
Output: (-1, -1, 5)

Analysis

This was a difficult challenge to get my head around!

Eventually I deduced that to match the examples, the line

If $x < length(@seen) append $seen[$x] to @ans

should read append $seen[$#seen - $x] to @ans. In other words, the element to be appended is not the $xth element of @seen, but the $xth element counting back from the end.

Alternatively, perhaps 'newest at the front' means adding successive elements to the start of @seen - like Perl unshift - but that does not match the @seen shown for example 2.

Once I figured that out, the coding just follows the challenge text.

I have yet to discover a real-world use case for this algorithm!

Perl Weekly’s review

from PW issue 745

A simple, effective and useful Perl implementation that uses little code to accurately address both issues. Without superfluous abstraction or flourish, Peter concentrates on the fundamental algorithmic requirements. It is an example of "get the job done" programming.

Try it 

Try running the script with any input:



example: 6, 4, -1, 3, -1, 5, 7, 8, -1, -1, -1, -1

Script


#!/usr/bin/perl

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

use v5.26;    # The Weekly Challenge - 2025-10-27
use utf8;     # Week 345 - task 2 - Last visitor
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';
use Encode;

last_visitor(5, -1, -1);
last_visitor(3, 7, -1, -1, -1);
last_visitor(2, -1, 4, -1, -1);
last_visitor(10, 20, -1, 30, -1, -1);
last_visitor(-1, -1, 5, -1);

sub last_visitor {
    
    my (@ints, @ans, @seen, $i, $x);
    
    # initialise
    @ints = @_;
    $x = 0;
    
    for $i (0 .. $#ints) {
        
        # if $ints[i] is +ve push it onto @seen
        if ($ints[$i] > 0) {
            push @seen, $ints[$i];
            $x = 0;

        # if $ints[$i] is -1 ...
        } elsif ($ints[$i] == -1) {
            
            # ... and $x <= length of @seen
            if ($x <= $#seen) {
                
                # push $x'th from last element of @seen onto @ans 
                push @ans, $seen[$#seen - $x];          
            } else {
                
                #  else push -1 onto @ans
                push @ans, -1;
            }
            
            # increment no of consecutive -1s
            $x ++;
        }
    }
    say qq[\nInput:  (] . join(', ', @ints) . ')';
    say qq[Output: (] . join(', ', @ans) . ')';
}

16 lines of code

Output from script


Input:  (5, -1, -1)
Output: (5, -1)

Input:  (3, 7, -1, -1, -1)
Output: (7, 3, -1)

Input:  (2, -1, 4, -1, -1)
Output: (2, 4, 2)

Input:  (10, 20, -1, 30, -1, -1)
Output: (20, 30, 20)

Input:  (-1, -1, 5, -1)
Output: (-1, -1, 5)

 

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