# Perl Weekly Challenge 184.

My solutions (task 1 and task 2 ) to the The Weekly Challenge - 184.

Submitted by: Mohammad S Anwar 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’)

#+endexample

If I assume that the first two characters are to be replaced without checking at all what they are, there is a very simple solution: I get the arguments from `@ARGV`, `substitute` the first two characters by a string using Perl’s magic increment of strings and the capability of executing code in the replacement part of a substitution. The result is a compact oneliner.

``````perl -E '\$i="00"; say join ", ", map {s/../\$i++/e; \$_} @ARGV' ab1234 cd5678 ef1342
perl -E '\$i="00"; say join ", ", map {s/../\$i++/e; \$_} @ARGV' pq1122 rs3334
``````

Results:

``````001234, 015678, 021342
001122, 013334
``````

The full code is essentially the same, save for checking that the conditions of the problem are satisfied

`````` 1  # Perl weekly challenge 184
2  # Task 1:  Sequence Number
3  #
5  use v5.36;
6  die <<"EOF" unless @ARGV;
7  Usage: \$0 s1 [s2 ...]
8  to replace the first 2 characters of strings S1 S2...
9  by a two digit increasing code.
10  The strings should be of the form lldddd where l is a letter a..z
11  and d a digit 0..9.
12  EOF
13  die "More than 100 strings" if @ARGV>100;
14  my \$counter="00";
15  say join ", ",
16      map {m/^[a-z]{2}\d{4}\$/||die "Bad format \$_\n"; s/../\$counter++/e; \$_}
17      @ARGV;
``````

Example:

``````./ch-1.pl ab1234 cd5678 ef1342
./ch-1.pl pq1122 rs3334
``````

Results:

``````001234, 015678, 021342
001122, 013334
``````

Examples with mistakes:

``````./ch-1.pl Ab1234 cd5678 ef1342
./ch-1.pl 001234 cd5678 ef1342
./ch-1.pl ab123 cd5678 ef1342
``````

Results:

``````Bad format Ab1234
``````

The first program was completely tolerant. The full version version is dumb and extremely intolerant.

``````Submitted by: Mohammad S Anwar
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], , [4,5]] and [['p','q','r'], ['s'], ['t']]
``````

I obtain the input from `@ARGV` and assume it is in the correct format. Then I can split each argument on space and store each character on an array of numbers or letters. I use the new ```for my(...)``` construction to iterate over such arrays building an array of arrays of numbers and an array of arrays of letters. Finally, I stringify and print the resulting arrays using a recursive function. The code can be condensed into a somewhat incomprehensible 3-liner.

Example 1:

``````perl -Mexperimental=for_list -MList::Util=reduce -E '
for my (\$N,\$L)(map {@n=@l=(); /^[0-9]\$/ and push @n, \$_ or push @l, \$_ for split " ";
[@n], [@l]} @ARGV){ push @N, \$N if @\$N; push @L, \$L if @\$L;} say p(@N), " and ", p(@L);
sub p(@X){ "[". join(", ", map{ref \$_?p(@\$_):\$_} @X) ."]"}
' 'a 1 2 b 0' '3 c 4 d'
``````

Results:

``````[[1, 2, 0], [3, 4]] and [[a, b], [c, d]]
``````

Example 2:

``````perl -Mexperimental=for_list -MList::Util=reduce -E '
for my (\$N,\$L)(map {@n=@l=(); /^[0-9]\$/ and push @n, \$_ or push @l, \$_ for split " ";
[@n], [@l]} @ARGV){ push @N, \$N if @\$N; push @L, \$L if @\$L;} say p(@N), " and ", p(@L);
sub p(@X){ "[". join(", ", map{ref \$_?p(@\$_):\$_} @X) ."]"}
' '1 2' 'p q r' 's 3' '4 5 t'
``````

Results:

``````[[1, 2], , [4, 5]] and [[p, q, r], [s], [t]]
``````

The full code is

`````` 1  # Perl weekly challenge 184
2  # Task 2:  Split Array
3  #
5  use v5.36;
6  use experimental qw(for_list);
7  use List::Util qw(reduce);
8
9  sub arr2str(@X){ # recursively converts array to string
10      "[" . join(", ", map{ref \$_ eq "ARRAY"? arr2str(@\$_):\$_} @X) . "]"
11  }
12
13  die <<EOF unless @ARGV;
14  Usage: \$0 S1 [S2...]
15  to split strings S1, S2... into arrays of numbers and letters.
16  Each string should contain space separated single letters a-z and/or digits 0-9.
17  EOF
18  for(@ARGV){ # check arguments
19      die "Wrong format: \$_" unless /^[a-z0-9](\s+[a-z0-9])*\$/;
20  }
21
22  my (@numbers_arr, @letters_arr); # arrays of array refs
23  for my (\$numbers,\$letters)( # array refs
24      map { # separate each arg into number and letters array refs.
25          my(@numbers, @letters);
26          /^[0-9]\$/ and push @numbers, \$_ or push @letters, \$_ for split " ";
27  	[@numbers], [@letters]
28     } @ARGV
29  ) {
30     push @numbers_arr, \$numbers if @\$numbers; # ignore empty arrays
31     push @letters_arr, \$letters if @\$letters;
32  }
33  say arr2str(@numbers_arr), " and ", arr2str(@letters_arr);
``````

Examples:

``````./ch-2.pl 'a 1 2 b 0' '3 c 4 d'
./ch-2.pl '1 2' 'p q r' 's 3' '4 5 t'
``````

Results:

``````[[1, 2, 0], [3, 4]] and [[a, b], [c, d]]
[[1, 2], , [4, 5]] and [[p, q, r], [s], [t]]
``````
Written on September 26, 2022