# Perl Weekly Challenge 263.

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

# Task 1: Target Index

``````Submitted by: Mohammad Sajid Anwar
You are given an array of integers, @ints and a target element \$k.

Write a script to return the list of indices in the sorted array where
the element is same as the given target element.

Example 1
Input: @ints = (1, 5, 3, 2, 4, 2), \$k = 2
Output: (1, 2)

Sorted array: (1, 2, 2, 3, 4, 5)
Target indices: (1, 2) as \$ints[1] = 2 and \$k[2] = 2
Example 2
Input: @ints = (1, 2, 4, 3, 5), \$k = 6
Output: ()

No element in the given array matching the given target.
Example 3
Input: @ints = (5, 3, 2, 4, 2, 1), \$k = 4
Output: (4)

Sorted array: (1, 2, 2, 3, 4, 5)
Target index: (4) as \$ints[4] = 4
``````

The task seems straightforward: sort the entries and filter the indices. I assume the arguments are in @ARGV starting with k.

Example 1:

``````perl -E '
\$k=shift; @x=sort{\$a<=>\$b}@ARGV; say "k=\$k, ints=(@ARGV) -> ", join " ", "(", grep({\$x[\$_]==\$k} (0..@x-1)), ")";
' 2 1 5 3 2 4 2
``````

Results:

``````k=2, ints=(1 5 3 2 4 2) -> ( 1 2 )
``````

Example 2:

``````perl -E '
\$k=shift; @x=sort{\$a<=>\$b}@ARGV; say "k=\$k, ints=(@ARGV) -> ", join " ", "(", grep({\$x[\$_]==\$k} (0..@x-1)), ")";
' 6 1 2 4 3 5
``````

Results:

``````k=6, ints=(1 2 4 3 5) -> ( )
``````

Example 3:

``````perl -E '
\$k=shift; @x=sort{\$a<=>\$b}@ARGV; say "k=\$k, ints=(@ARGV) -> ", join " ", "(", grep({\$x[\$_]==\$k} (0..@x-1)), ")";
' 4 5 3 2 4 2 1
``````

Results:

``````k=4, ints=(5 3 2 4 2 1) -> ( 4 )
``````

The full code follows:

`````` 1  # Perl weekly challenge 263
2  # Task 1:  Target Index
3  #
4  # See https://wlmb.github.io/2024/04/01/PWC263/#task-1-target-index
5  use v5.36;
6  die <<~"FIN" unless @ARGV;
7      Usage: \$0 k N0 [N1...]
8      to find the indices of the array N0 N1... (after sorting) for which
9      N_i=k
10      FIN
11  my \$k=shift;
12  my @sorted=sort{\$a<=>\$b}@ARGV;
13  say "k=\$k, ints=(@ARGV) -> ",
14      join " ", "(", grep({\$sorted[\$_]==\$k} (0..@sorted-1)), ")";
``````

Example:

``````for i in "2 1 5 3 2 4 2" "6 1 2 4 3 5" "4 5 3 2 4 2 1";do ./ch-1.pl `echo \$i`; done
``````

Results:

``````k=2, ints=(1 5 3 2 4 2) -> ( 1 2 )
k=6, ints=(1 2 4 3 5) -> ( )
k=4, ints=(5 3 2 4 2 1) -> ( 4 )
``````

# Task 2: Merge Items

``````Submitted by: Mohammad Sajid Anwar
You are given two 2-D array of positive integers, \$items1 and \$items2
where element is pair of (item_id, item_quantity).

Write a script to return the merged items.

Example 1
Input: \$items1 = [ [1,1], [2,1], [3,2] ]
\$items2 = [ [2,2], [1,3] ]
Output: [ [1,4], [2,3], [3,2] ]

Item id (1) appears 2 times: [1,1] and [1,3]. Merged item now (1,4)
Item id (2) appears 2 times: [2,1] and [2,2]. Merged item now (2,3)
Item id (3) appears 1 time: [3,2]
Example 2
Input: \$items1 = [ [1,2], [2,3], [1,3], [3,2] ]
\$items2 = [ [3,1], [1,3] ]
Output: [ [1,8], [2,3], [3,3] ]
Example 3
Input: \$items1 = [ [1,1], [2,2], [3,3] ]
\$items2 = [ [2,3], [2,4] ]
Output: [ [1,1], [2,9], [3,3] ]
``````

As items to be merged may be part of the same list, it seems unnecesary to keep them in two lists. I use PDL to easily convert between several nested arrays to a simple list which I iterate using the new `for_list`. I accumulate values in a hash and finally, I print key,value pairs. This fits a longish one-liner.

Example 1:

``````perl -Mexperimental=for_list -MPDL -E '
push @e, pdl(\$_)->list for @ARGV;for my(\$x,\$y)(@e){\$v{\$x}+=\$y};@r=map {"[\$_,\$v{\$_}]"} keys %v;say "@ARGV -> [@r]";
' "[[1,2],[2,3],[1,3],[3,2]]" "[[3,1],[1,3]]"
``````

Results:

``````[[1,2],[2,3],[1,3],[3,2]] [[3,1],[1,3]] -> [[1,8] [3,3] [2,3]]
``````

I got the expected results but unsorted.

Example 2:

``````perl -Mexperimental=for_list -MPDL -E '
push @e, pdl(\$_)->list for @ARGV;for my(\$x,\$y)(@e){\$v{\$x}+=\$y};@r=map {"[\$_,\$v{\$_}]"} keys %v;say "@ARGV -> [@r]";
' "[[1,2],[2,3],[1,3],[3,2]]" "[[3,1],[1,3]]"
``````

Results:

``````[[1,2],[2,3],[1,3],[3,2]] [[3,1],[1,3]] -> [[2,3] [3,3] [1,8]]
``````

Example 3:

``````perl -Mexperimental=for_list -MPDL -E '
push @e, pdl(\$_)->list for @ARGV;for my(\$x,\$y)(@e){\$v{\$x}+=\$y};@r=map {"[\$_,\$v{\$_}]"} keys %v;say "@ARGV -> [@r]";
' "[[1,1],[2,2],[3,3]]" "[[2,3],[2,4]]"
``````

Results:

``````[[1,1],[2,2],[3,3]] [[2,3],[2,4]] -> [[1,1] [2,9] [3,3]]
``````

The full code is similar. I just add some checks and I sort the result.

`````` 1  # Perl weekly challenge 263
2  # Task 2:  Merge Items
3  #
4  # See https://wlmb.github.io/2024/04/01/PWC263/#task-2-merge-items
5  use v5.36;
6  use PDL; # use the perl data language to convert the input to a list of keys-values
7  use experimental qw(for_list); # use for list to process key-value pairs
8  die <<~"FIN" unless @ARGV;
9      Usage: \$0 "[[K11,V11],[K12,V12]...]]" "[[K21,V21],[K22,V22],...]" ...
10      to accumulate all values Vij corresponding to each unique key Kn=Kij
11      FIN
12  my @keyvals;
13  push @keyvals, pdl(\$_)->list for @ARGV;
14  my %merged;
15  for my(\$key, \$val)(@keyvals){
16      \$merged{\$key}+=\$val
17  };
18  my @result = map {"[\$_,\$merged{\$_}]"} sort {\$a cmp \$b} keys %merged;
19  say "@ARGV -> [@result]";
``````

Example:

``````./ch-2.pl "[[1,2],[2,3],[1,3],[3,2]]" "[[3,1],[1,3]]"
./ch-2.pl "[[1,2],[2,3],[1,3],[3,2]]" "[[3,1],[1,3]]"
./ch-2.pl "[[1,1],[2,2],[3,3]]" "[[2,3],[2,4]]"
``````

Results:

``````[[1,2],[2,3],[1,3],[3,2]] [[3,1],[1,3]] -> [[1,8] [2,3] [3,3]]
[[1,2],[2,3],[1,3],[3,2]] [[3,1],[1,3]] -> [[1,8] [2,3] [3,3]]
[[1,1],[2,2],[3,3]] [[2,3],[2,4]] -> [[1,1] [2,9] [3,3]]
``````

Note that I may more or less than two input arrays.

Other examples:

``````./ch-2.pl "[[1,2],[2,3],[1,3],[3,2]]"
./ch-2.pl "[[1,2],[2,3],[1,3],[3,2]]" "[[3,1],[1,3]]" "[[1,1],[2,2],[3,3]]" "[[2,3],[2,4]]"
``````

Results:

``````[[1,2],[2,3],[1,3],[3,2]] -> [[1,5] [2,3] [3,2]]
[[1,2],[2,3],[1,3],[3,2]] [[3,1],[1,3]] [[1,1],[2,2],[3,3]] [[2,3],[2,4]] -> [[1,9] [2,12] [3,6]]
``````
Written on April 1, 2024