## Advent Calendar - December 13, 2023

Wednesday, Dec 13, 2023| Tags: Raku

### |   Day 12   |   Day 13   |   Day 14   |

The gift is presented by `Arne Sommer`. Today he is talking about his solution to The Weekly Challenge - 222. This is re-produced for `Advent Calendar 2023` from the original post.

## Raku Members

### Challenge #222.1: Matching Members

``````You are given a list of positive integers, @ints.
Write a script to find the total matching members after sorting the list increasing order.

Example 1:

Input: @ints = (1, 1, 4, 2, 1, 3)
Output: 3

Original list: (1, 1, 4, 2, 1, 2)
Sorted list  : (1, 1, 1, 2, 3, 4)

Compare the two lists, we found 3 matching members (1, 1, 2).

Example 2:

Input: @ints = (5, 1, 2, 3, 4)
Output: 0

Original list: (5, 1, 2, 3, 4)
Sorted list  : (1, 2, 3, 4, 5)

Compare the two lists, we found 0 matching members.

Example 3:

Input: @ints = (1, 2, 3, 4, 5)
Output: 5

Original list: (1, 2, 3, 4, 5)
Sorted list  : (1, 2, 3, 4, 5)

Compare the two lists, we found 5 matching members.
``````

``````#! /usr/bin/env raku

unit sub MAIN (*@ints where @ints.elems > 1 && all(@ints) ~~ Int
&& all(@ints) > 0);                # [1]

say (@ints Z @ints.sort).grep( { \$_[0] eq \$_[1] }).elems;  # [2]
# D  # A ############### # B ##################### # C ##
``````

`[1]` At least two elements, all of them integers, and greater than zero.

`[2]` We start with the list itself and a sorted copy, merging them with the `Z (zip)` operator `[A]`. The result is a list with pair objects; one element from the original list, and one from the sorted one. Then we use grep to keep the pairs where the two values are equal `[B]`. Then we count the number of elements (i.e. pairs) in the resulting list `[C]` and print that number `[D]`.

See docs.raku.org/routine/Z for more information about the `infix zip` operator `Z`.

Running it:

``````\$ ./matching-members 1 1 4 2 1 3
3

\$ ./matching-members 5 1 2 3 4
0

\$ ./matching-members 1 2 3 4 5
5
``````

Looking good.

### Challenge #222.2: Last Member

``````You are given an array of positive integers, @ints.

Write a script to find the last member if found otherwise return 0. Each turn
pick 2 biggest members (x, y) then decide based on the following conditions,
continue this until you are left with 1 member or none.

if x == y then remove both members
if x != y then remove both members and add new member (y-x)

Example 1:

Input: @ints = (2, 7, 4, 1, 8, 1)
Output: 1

Step 1: pick 7 and 8, we remove both and add new member 1 => (2, 4, 1, 1, 1).
Step 2: pick 2 and 4, we remove both and add new member 2 => (2, 1, 1, 1).
Step 3: pick 2 and 1, we remove both and add new member 1 => (1, 1, 1).
Step 4: pick 1 and 1, we remove both => (1).

Example 2:

Input: @ints = (1)
Output: 1

Example 3:

Input: @ints = (1, 1)
Output: 0

Step 1: pick 1 and 1, we remove both and we left with none.
``````

``````#! /usr/bin/env raku

unit sub MAIN (*@ints where @ints.elems > 0 && all(@ints) ~~ Int
&& all(@ints) > 0,                     # [1]
:v(:\$verbose));

@ints = @ints>>.Int.sort.reverse;                                  # [2]

while @ints.elems > 1                                              # [3]
{
say ":Sorted: @ints[]" if \$verbose;

my \$y    = @ints.shift;                                          # [4]
my \$x    = @ints.shift;                                          # [4]
my \$diff = \$y - \$x;                                              # [5]

say ":List:   @ints[] { \$diff ?? "| add \$diff (source: \$y - \$x)" \
!! "| no add (source \$y == \$x)" }" if \$verbose;

if \$diff                                                         # [6]
{
@ints.push: \$diff;                                             # [6a]
@ints = @ints.sort.reverse;                                    # [6b]
}
}

say @ints.elems ?? @ints[0] !! 0;                                  # [7]
``````

`[1]` At least 1 element, all of them must be positve integers.

`[2]` Coerce the values to integers (from the undecided IntStr that we get from using the command line), just to make the verbose mode output looks nice. We sort the values with the highest one first.

`[3]` As long as there are at least two elements left,

`[4]` Get the two highest values.

`[5]` Get the difference. Note the order we got the values in [4], ensuring a non-negative difference here.

`[6]` Do we have a difference? If so, add the difference to the list [6a], and resort the list [6b] - so that it always is sorted when we start a new iteration (in [3]).

`[7]` If we have elements in the list (just one, really), print that value. If not, print 0.

Running it:

``````\$ ./last-member 2 7 4 1 8 1
1

\$ ./last-member 1
1

\$ ./last-member 1 1
0
``````

Looking good.

With verbose mode:

``````\$ ./last-member -v 2 7 4 1 8 1
:Sorted: 8 7 4 2 1 1
:List:   4 2 1 1 | add 1 (source: 8 - 7)
:Sorted: 4 2 1 1 1
:List:   1 1 1 | add 2 (source: 4 - 2)
:Sorted: 2 1 1 1
:List:   1 1 | add 1 (source: 2 - 1)
:Sorted: 1 1 1
:List:   1 | no add (source 1 == 1)
1

\$ ./last-member -v 1
1

\$ ./last-member -v 1 1
:Sorted: 1 1
:List:    | no add (source 1 == 1)
0
``````

And that’s it.

If you have any suggestion then please do share with us perlweeklychallenge@yahoo.com.

## SO WHAT DO YOU THINK ?

If you have any suggestions or ideas then please do share with us.