Perl Weekly Challenge 184: Sequence Number and Split Array

These are some answers to the Week 184 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 Oct. 2, 2022 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: Sequence Number

You are given list of strings in the format aa9999 i.e. first 2 characters can be anything ‘a-z’ followed by 4 digits ‘0-9’.

Write a script to replace the first two characters with sequence starting with ‘00’, ‘01’, ‘02’ etc.

Example 1

Input: @list = ( 'ab1234', 'cd5678', 'ef1342')
Output: ('001234', '015678', '021342')

Example 2

Input: @list = ( 'pq1122', 'rs3334')
Output: ('001122', '013334')

Sequence Number in Raku

The program is fairly straight forward. For various reasons, I found that using the subst method was slightly more efficient (code-wise) than using a regex substitution.

for <ab1234 cd5678 ef1342>, <pq1122 rs3334> -> @test {
    my $i = 0;
    my @out;
    for @test {
        push @out, .subst(/^<[a..z]>**2/, $i.fmt("%02d"));
        $i++;
    }
    say "@test[]  =>  @out[]";
}

This program displays the following output:

$ raku ./sequence-number.raku
ab1234 cd5678 ef1342  =>  001234 015678 021342
pq1122 rs3334  =>  001122 013334

Sequence Number in Perl

This is essentially a port to Perl of the Raku program above:

use strict;
use warnings;
use feature qw/say/;

for my $test ([<ab1234 cd5678 ef1342>], [<pq1122 rs3334>]) {
    my $i = 0;
    my @out = @$test;
    for (@out) {
        my $count = sprintf("%02d", $i);
        s/^[a-z]{2}/$count/;
        $i++;
    }
    say "@$test  =>  @out";
}

This program displays the following output:

$ perl ./sequence-number.pl
ab1234 cd5678 ef1342  =>  001234 015678 021342
pq1122 rs3334  =>  001122 013334

Task 2: Split Array

You are given list of strings containing 0-9 and a-z separated by space only.

Write a script to split the data into two arrays, one for integers and one for alphabets only.

Example 1

Input: @list = ( 'a 1 2 b 0', '3 c 4 d')
Output: [[1,2,0], [3,4]] and [['a','b'], ['c','d']]

Example 2

Input: @list = ( '1 2', 'p q r', 's 3', '4 5 t')
Output: [[1,2], [3], [4,5]] and [['p','q','r'], ['s'], ['t']]

Split Array in Raku

Using grep to keep either letters or numerals:

for ('a 1 2 b 0', '3 c 4 d'), ('1 2', 'p q r', 's 3', '4 5 t') -> @test {
    my (@letters, @digits);
    for @test -> $item {
        append @letters, grep {  /<alpha>+/ }, $item.split(/\s+/);
        append @digits, grep { /\d+/ }, $item.split(/\s+/);
    }
    .say for @letters, @digits;
}

This program displays the following output:

$ raku ./split-array.raku
[a b c d]
[1 2 0 3 4]
[p q r s t]
[1 2 3 4 5]

Split Array in Perl

This is a port to Perl of the above Raku program:

use strict;
use warnings;
use feature qw/say/;

for my $test (['a 1 2 b 0', '3 c 4 d'], ['1 2', 'p q r', 's 3', '4 5 t']) {
    my (@letters, @digits);
    for my $item (@$test) {
        push @letters, grep { /[a-zA-Z]+/ } split /\s+/, $item;
        push @digits, grep { /\d+/ } split /\s+/, $item;;
    }
    say  "@letters \n@digits";
}

This program displays the following output:

$ perl  ./split-array.pl
a b c d
1 2 0 3 4
p q r s t
1 2 3 4 5

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 October 9, 2022. 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.