by Arne Sommer

# Target Merge with Raku

[283] Published 4. April 2024.

This is my response to The Weekly Challenge #263.

## Challenge #263.1: Target Index

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 \$ints[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 ```
File: target-index ```#! /usr/bin/env raku unit sub MAIN (Int \$k, # [1] *@ints where @ints.elems > 0 && all(@ints) ~~ Int, # [2] :v(:\$verbose)); say ": Sorted: { @ints.sort.join(",") }" if \$verbose; say '(', (@ints.sort.grep: \$k, :k).join(", "), ')'; # [3] ```

[1] First the `\$k` value, which must be an integer.

[2] Then the array of integers, at least one element.

[3] `sort` the array, then use `grep` to filter out the `\$k` values - or rather the indices instead of the values themselves as indicated with the `:k` adverb. Pretty print the result.

See docs.raku.org/routine/grep for more information about `grep`.

See Unique Rank with Raku for a short description of the `:k` (keys) adverb.

Running it:

```\$ ./target-index 2 1 5 3 2 4 2 (1, 2) \$ ./target-index 6 1 2 4 3 5 () \$ ./target-index 4 5 3 2 4 2 1 (4) ```

With verbose mode:

```: Sorted: 1,2,2,3,4,5 (1, 2) \$ ./target-index -v 6 1 2 4 3 5 : Sorted: 1,2,3,4,5 () \$ ./target-index -v 4 5 3 2 4 2 1 : Sorted: 1,2,2,3,4,5 (4) ```

## Challenge #263.2: Merge Items

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] ] ```
File: merge-items ```#! /usr/bin/env raku unit sub MAIN (\$items1, \$items2, :v(:\$verbose)); # [1] my @items1 = \$items1.split("|")>>.words>>.Int; # [2] my @items2 = \$items2.split("|")>>.words>>.Int; # [2] if \$verbose { say ": items1: { @items1.raku }"; say ": items2: { @items2.raku }"; } my %count; # [3] for @items1 -> \$item # [4] { say ": item1 ID \$item[0] with frequency \$item[1]"; %count{\$item[0]} += \$item[1]; # [4a] } for @items2 -> \$item # [5] { say ": item2 ID \$item[0] with frequency \$item[1]"; %count{\$item[0]} += \$item[1]; # [5a] } my @output; # [6] for sort keys %count -> \$key # [7] { @output.push: (\$key.Int, %count{\$key}); # [7a] } say @output.raku; # [8] ```

[1] The two two dimentional arrays. See the "Running it" section below for how to specify the values.

[2] Convert the strings into two dimentional arrays.

[3] We are going to count the frequencies, using this hash.

[4] Iterate over the first array; add the count (the second part of the pair) to the value (the first part of the pair) in the hash [4a].

[5] As above, for the second array.

[6] The two dimentional array for the output output will end up here.

[7] Iterate over the keys (the original values) in sorted order. Add the key and the value (frequency) as a pair to the result. Note the coersion to integer, as it is a string otherwise.

[8] Print the result, uisng the `raku` method.

See docs.raku.org/routine/raku for more information about `raku`.

Running it:

```\$ ./merge-items "1 1 | 2 1 | 3 2" "2 2 | 1 3" [(1, 4), (2, 3), (3, 2)] \$ ./merge-items "1 2 | 2 3 | 1 3 | 3 2" "3 1 | 1 3" [(1, 8), (2, 3), (3, 3)] \$ ./merge-items "1 1 | 2 2 | 3 3" "2 3 | 2 4" [(1, 1), (2, 9), (3, 3)] ```

Looking good.

With verbose mode:

```\$ ./merge-items -v "1 1 | 2 1 | 3 2" "2 2 | 1 3" : items1: [(1, 1), (2, 1), (3, 2)] : items2: [(2, 2), (1, 3)] : item1 ID 1 with frequency 1 : item1 ID 2 with frequency 1 : item1 ID 3 with frequency 2 : item2 ID 2 with frequency 2 : item2 ID 1 with frequency 3 [(1, 4), (2, 3), (3, 2)] \$ ./merge-items -v "1 2 | 2 3 | 1 3 | 3 2" "3 1 | 1 3" : items1: [(1, 2), (2, 3), (1, 3), (3, 2)] : items2: [(3, 1), (1, 3)] : item1 ID 1 with frequency 2 : item1 ID 2 with frequency 3 : item1 ID 1 with frequency 3 : item1 ID 3 with frequency 2 : item2 ID 3 with frequency 1 : item2 ID 1 with frequency 3 [(1, 8), (2, 3), (3, 3)] \$ ./merge-items -v "1 1 | 2 2 | 3 3" "2 3 | 2 4" : items1: [(1, 1), (2, 2), (3, 3)] : items2: [(2, 3), (2, 4)] : item1 ID 1 with frequency 1 : item1 ID 2 with frequency 2 : item1 ID 3 with frequency 3 : item2 ID 2 with frequency 3 : item2 ID 2 with frequency 4 [(1, 1), (2, 9), (3, 3)] ```

And that's it.