This is my response to The Weekly Challenge #184.
aa9999
i.e. first 2 characters
can be anything 'a-z'
followed by 4 digits '0-9'
.
'00'
, '01'
, '02'
etc.
Input: @list = ( 'ab1234', 'cd5678', 'ef1342')
Output: ('001234', '015678', '021342')
Example 2:
Input: @list = ( 'pq1122', 'rs3334')
Output: ('001122', '013334')
I have chosen to hard code the examples.
File: sequence-number
#! /usr/bin/env raku
my @list1 = ('ab1234', 'cd5678', 'ef1342'); # [1]
my @list2 = ('pq1122', 'rs3334'); # [1]
say sequence-number(@list1); # [2]
say sequence-number(@list2); # [2]
sub sequence-number (@list) # [2a]
{
my @return;
for @list -> $string # [3]
{
state $count = 0; # [4]
@return.push($count.fmt('%02d') ~ $string.substr(2,4)); # [5]
$count++; # [4a]
}
return @return; # [5]
}
[1] The two example arrays.
[2] Print the result of transforming the arrays.
[3] Iterate over the strings in the input array.
[4] I have chosen to use a state variable for the the counter. State variables are initialized only once (or initially, as it were), and retains the (previous) value thereafter.
See
docs.raku.org/syntax/state for
more information about the variable declarator state
.
[5] Start with the counter, as a two-digit number (courtesy of
fmt
, the method form of sprintf
)
and append the four last characters from the input string (courtesy of
substr
).
See
docs.raku.org/routine/fmt for
more information about fmt
.
Running it:
$ ./sequence-number
[001234 015678 021342]
[001122 013334]
Looking good. Except the brackets instead of parens and the missing quotes. One can argue that this is a result of the stringification caused by the printing, and that the Raku data structure adheres to the output. So I'll leave it here.
#! /usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use v5.20;
use feature 'signatures';
no warnings 'experimental::signatures';
my @list1 = ('ab1234', 'cd5678', 'ef1342');
my @list2 = ('pq1122', 'rs3334');
say sequence_number(@list1);
say sequence_number(@list2);
sub sequence_number (@list)
{
my @return;
for my $string (@list)
{
state $count = 0;
push(@return, sprintf('%02d', $count) . substr($string, 2, 4));
$count++;
}
return "(" . join(", ", map { "'$_'"} @return) . ")"; # [1]
}
[1] Printing arrays does not work out that well in Perl, so we stringify them manually. (See the discussion at the end of the perl part of «Split Array» for some more thoughts about the matter.
Running it gives the expected result.
$ ./sequence-number-perl
('001234', '015678', '021342')
('031122', '043334')
0-9
and a-z
separated by space
only.
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']]
File: split-array
#! /usr/bin/env raku
my @list1 = ('a 1 2 b 0', '3 c 4 d'); # [1]
my @list2 = ('1 2', 'p q r', 's 3', '4 5 t'); # [2]
say split-array(@list1); # [3]
say split-array(@list2); # [3]
sub split-array (@list) # [3a]
{
my @digits; # [4]
my @letters; # [5]
for @list -> $string # [6]
{
my @d-curr; # [7]
my @l-curr; # [8]
for $string.words -> $char # [9]
{
$char eq any(0..9) ?? @d-curr.push($char) !! @l-curr.push($char);
} # [10]
@digits.push: @d-curr if @d-curr; # [11]
@letters.push: @l-curr if @l-curr; # [12]
}
return (@digits, @letters); # [13]
}
[1] The values from example 1.
[2] The values from example 2.
[3] Print the new values, given by the «split-array» procedure ([3a]).
[4] We are going to collect the arrays of digits here.
[5] Ditto for the letters.
[6] Iterate over the input strings.
[7] The digits in the current input string will end up here.
[8] Ditto for the letters.
[9] Iterate over the individual characters in the string.
[10] Add the character to the correct array; letter or digit.
[11] Add the current list of digits to the global list of digits, if any.
[12] Ditto for the letters
[13] Return the list of list of digits, and the list of list of letters.
Running it:
$ ./split-array
([[1 2 0] [3 4]] [[a b] [c d]])
([[1 2] [3] [4 5]] [[p q r] [s] [t]])
Looking good. Except the extra set of parens and the missing commas and quotes. Let us argue, once again, that this is a feature of the stringifiaction process - and not a property of the internal data structure.
ARRAY(0x559b775cf1b0)
).
File: split-array-perl
#! /usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use feature 'signatures';
no warnings 'experimental::signatures';
use Perl6::Junction 'any';
my @list1 = ('a 1 2 b 0', '3 c 4 d');
my @list2 = ('1 2', 'p q r', 's 3', '4 5 t');
say split_array(@list1);
say split_array(@list2);
sub split_array (@list)
{
my @digits;
my @letters;
for my $string (@list)
{
my @d_curr;
my @l_curr;
for my $char (split(" ", $string))
{
$char eq any(0..9) ? push(@d_curr, $char) : push(@l_curr, $char);
}
push(@digits, "[" . join(",", @d_curr) . "]") if @d_curr; # [1]
push(@letters, "[" . join(",", map { "'" . $_ . "'" } @l_curr) . "]") # [1]
if @l_curr;
}
my @return;
push(@return, "[" . join (", ", @digits) . "]") if @digits; # [1]
push(@return, "[" . join (", ", @letters) . "]") if @letters; # [1]
return join(" and ", @return); # [2]
}
[1] Note that we push a complete string with brackets commas and quotes (in the case of letters) instead of an array.
[2] The icing on the cake is the addition of the word «and» between the two arrays. I do not really think that we should take the output of the examples literally, but it sure is fun to do so anyway...
Running it gives the same values as the Raku version, but with the commas and quoted letters in place:
$ ./split-array-perl
[[1,2,0],[3,4]] and [['a','b'],['c','d']]
[[1,2], [3], [4,5]] and [['p','q','r'], ['s'], ['t']]
See United States of Anagrams with Raku - Part 3: Multigrams for how to create multi word anagrams.
And that's it.