Camel
Peter
Peter Campbell Smith

Words and shopping

Weekly challenge 353 — 22 December 2025

Week 353: 22 Dec 2025

Task 2

Task — Validate coupon

You are given three arrays, @codes, @names and @status. Write a script to validate codes in the given array.

A code is valid when the following conditions are true:

  • $codes[$i] is non-empty and consists only of alphanumeric characters (a-z, A-Z, 0-9) and underscores (_).
  • $names[$i] is one of the following four categories: "electronics", "grocery", "pharmacy", "restaurant".
  • $status[$i] is true.

Return an array of booleans indicating validity: $output[$i] is true if and only if $codes[$i], $names[$i] and $status[$i] are all valid.

Examples


Example 1
Input: @codes  = ('A123', 'B_456', 'C789', 'D@1', 'E123')
       @names  = ('electronics', 'restaurant',
   'electronics', 'pharmacy', 'grocery')
       @status = ('true', 'false', 'true', 'true', 'true')
Output: (true, false, true, false, true)

Example 2
Input: @codes  = ('Z_9', 'AB_12', 'G01', 'X99', 'test')
       @names  = ('pharmacy', 'electronics', 'grocery',
   'electronics', 'unknown')
       @status = ('true', 'true', 'false', 'true', 'true')
Output: (true, true, false, true, false)

Example 3
Input: @codes  = ('_123', '123', '', 'Coupon_A', 'Alpha')
       @names  = ('restaurant', 'electronics',
   'electronics', 'pharmacy', 'grocery')
       @status = ('true', 'true', 'false', 'true', 'true')
Output: (true, true, false, true, true)

Example 4
Input: @codes  = ('ITEM_1', 'ITEM_2', 'ITEM_3', 'ITEM_4')
       @names  = ('electronics', 'electronics', 'grocery',
   'grocery')
       @status = ('true', 'true', 'true', 'true')
Output: (true, true, true, true)

Example 5
Input: @codes  = ('CAFE_X', 'ELEC_100', 'FOOD_1',
   'DRUG_A', 'ELEC_99')
       @names  = ('restaurant', 'electronics', 'grocery',
   'pharmacy', 'electronics')
       @status = ('true', 'true', 'true', 'true', 'false')
Output: (true, true, true, true, false)

Analysis

In one sense, this is quite a trivial exercise, but in real life it may not be. We can imagine that a file of code/name/status is uploaded to a store at 07:00 every morning and has to be processed according to this challenge before the store opens at 08:00. As the volume of business increases over time, the processing time of the file becomes critical, and the necessity to do it most efficiently increases.

So the question is: what order of applying the three criteria is most efficient?

Knowing nothing about the likelihood of each criterion failing, I took the view that:

  • The fastest check is status: all we need to do is check $status eq 'true'. So let's do that first. Note that if it's false, Perl will not evaluate the other two criteria - which is good!
  • I then check $name. There are only a few possibilities, so I used a hash to test $good{$name}. %good is a hash where the keys are the valid names and the values are all 1, so Perl evaluates $good{name} as true if the hash element exists and false otherwise. Perl's hash function is quite fast.
  • And lastly I check that $code has at least the right format. That uses a regular expression, which is probably the slowest comparison.

In real life, I would look at the data to see which of the three parameters was most likely to return false, and check that first. For example, maybe this particular store doesn't stock electronics, so checking $name first would be best, because it would avoid the other two checks for all the electronic items.

And in real real life I had to code something very like this for a credit control department of a telecomms company.

Try it 

Try running the script with any input:



example: A123, B234, ccc, 789D



example: electronics, sausages, grocery, pharmacy



example: true, true, false, true

Script


#!/usr/bin/perl

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

use v5.26;    # The Weekly Challenge - 2025-12-22
use utf8;     # Week 353 - task 2 - Validate coupon
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';
use Encode;

validate_coupon(['A123', 'B_456', 'C789', 'D@1', 'E123'],
    ['electronics', 'restaurant', 'electronics', 'pharmacy', 'grocery'],
    ['true', 'false', 'true', 'true', 'true']);
validate_coupon(['Z_9', 'AB_12', 'G01', 'X99', 'test'],
    ['pharmacy', 'electronics', 'grocery', 'electronics', 'unknown'],
    ['true', 'true', 'false', 'true', 'true']);
validate_coupon(['_123', '123', '', 'Coupon_A', 'Alpha'],
    ['restaurant', 'electronics', 'electronics', 'pharmacy', 'grocery'],
    ['true', 'true', 'false', 'true', 'true']);
validate_coupon(['ITEM_1', 'ITEM_2', 'ITEM_3', 'ITEM_4'],
    ['electronics', 'electronics', 'grocery', 'grocery'],
    ['true', 'true', 'true', 'true']);
validate_coupon(['CAFE_X', 'ELEC_100', 'FOOD_1', 'DRUG_A', 'ELEC_99'],
    ['restaurant', 'electronics', 'grocery', 'pharmacy', 'electronics'],
    ['true', 'true', 'true', 'true', 'false']);

sub validate_coupon {
    
    my ($codes, $names, $status, $result, %good);
    
    # initialise
    ($codes, $names, $status) = @_;
    %good = (electronics => 1, restaurant => 1, electronics => 1, pharmacy => 1, grocery => 1);
    
    # apply conditions
    $result .= ($status->[$_] eq 'true'
        and $good{$names->[$_]}
        and $codes->[$_] =~ m|^[a-z0-9_]+$|i) ? 'true, ' : 'false, '
        for (0 .. scalar @$codes - 1);
    
    # report
    say qq[\nInput:  \@codes  = ('] . join(q[', '], @$codes) . qq[')\n] .
        qq[        \@names  = ('] . join(q[', '], @$names) . qq[')\n] .
        qq[        \@status = ('] . join(q[', '], @$status) . q[')];
    say qq[Output: ] . substr($result, 0, -2);
}

Output


Input:  \@codes  = ('A123', 'B_456', 'C789', 'D\@1', 
                    'E123')
        \@names  = ('electronics', 'restaurant', 
                    'electronics', 'pharmacy', 'grocery')
        \@status = ('true', 'false', 'true', 'true', 
                    'true')
Output: true, false, true, false, true

Input:  \@codes  = ('Z_9', 'AB_12', 'G01', 'X99', 'test')
        \@names  = ('pharmacy', 'electronics', 'grocery',
                    'electronics', 'unknown')
        \@status = ('true', 'true', 'false', 'true', 
                    'true')
Output: true, true, false, true, false

Input:  \@codes  = ('_123', '123', '', 'Coupon_A',
                    'Alpha')
        \@names  = ('restaurant', 'electronics', 
                    'electronics', 'pharmacy', 'grocery')
        \@status = ('true', 'true', 'false', 'true',
                    'true')
Output: true, true, false, true, true

Input:  \@codes  = ('ITEM_1', 'ITEM_2', 'ITEM_3', 
                    'ITEM_4')
        \@names  = ('electronics', 'electronics',
		            'grocery', 'grocery')
        \@status = ('true', 'true', 'true', 'true')
Output: true, true, true, true

Input:  \@codes  = ('CAFE_X', 'ELEC_100', 'FOOD_1', 
                    'DRUG_A', 'ELEC_99')
        \@names  = ('restaurant', 'electronics',
                    'grocery', 'pharmacy', 'electronics')
        \@status = ('true', 'true', 'true', 'true', 
                    'false')
Output: true, true, true, true, false

 

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