Perl Weekly Challenge: Week 324

Challenge 1:

2D Array

You are given an array of integers and two integers $r amd $c.

Write a script to create two dimension array having $r rows and $c columns using the given array.

Example 1
Input: @ints = (1, 2, 3, 4), $r = 2, $c = 2
Output: ([1, 2], [3, 4])
Example 2
Input: @ints = (1, 2, 3), $r = 1, $c = 3
Output: ([1, 2, 3])
Example 3
Input: @ints = (1, 2, 3, 4), $r = 4, $c = 1
Output: ([1], [2], [3], [4])

This one is very easy with the only complication being, as it so often is, getting input in the script. I chose to make the first two command-line arguments $r, $c and the rest of them @ints.

@output is where will we put the new array,

my @output;

For each row, we copy the requisite number of elements into the new array. Originally, I was going to use a second loop, and add elements one at a time but I thought it would be more efficient to use .splice() to add an entire a row at a time,

for 1 .. $r {
    @output.push(@ints.splice(0, $c));
}

Now we print the new array. This line is a little more complicated than it needs to be but only so we can match the style of the output in the spec.

say q{(}, @output.map({ q{[} ~ @$_.join(q{, }) ~ q{]} }).join(q{, }), q{)};

(Full code on Github.)

The Perl version is mostly the same.

my @output;

for my $row (1 .. $r) {

The only difference is we have to add rows as array references in order to make @output a proper 2D array.

    push @output, [ splice @ints, 0, $c ];
}

say q{(}, (join q{, }, map { q{[} . (join q{, }, @{$_}) . q{]} } @output), q{)};

(Full code on Github.)

Challenge 2:

Total XOR

You are given an array of integers.

Write a script to return the sum of total XOR for every subset of given array.

Example 1
Input: @ints = (1, 3)
Output: 6

Subset [1],    total XOR = 1
Subset [3],    total XOR = 3
Subset [1, 3], total XOR => 1 XOR 3 => 2

Sum of total XOR => 1 + 3 + 2 => 6
Example 2
Input: @ints = (5, 1, 6)
Output: 28

Subset [5],       total XOR = 5
Subset [1],       total XOR = 1
Subset [6],       total XOR = 6
Subset [5, 1],    total XOR => 5 XOR 1 => 4
Subset [5, 6],    total XOR => 5 XOR 6 => 3
Subset [1, 6],    total XOR => 1 XOR 6 => 7
Subset [5, 1, 6], total XOR => 5 XOR 1 XOR 6 => 2

Sum of total XOR => 5 + 1 + 6 + 4 + 3 + 7 + 2 => 28
Example 3
Input: @ints = (3, 4, 5, 6, 7, 8)
Output: 480

Thanks to Rakus' powerful standard library, we have the tools to make this a one-liner. The input is brought in from the command-line in @*ARGS. The subsets are created from it with .combinations() Then we traverse these subsets with .map(). The total XOR for each subset can be calculated in one operation with [+^] and the sum of the totals is calculated with the apropriately named .sum(). Finally, we print out the result with .say().

@*ARGS.combinations.map({[+^] $_}).sum.say

(Full code on Github.)

For the Perl version, we don't have .combinations() but luckily I had code from previous challenges I could reuse.

my $sum = 0;

Unlike Raku, my combinations() only creates one size of combination at a time so a loop is needed to repeatedly call it with length of 1 to the size of @ints.

for my $i (1 .. scalar @ints) {
    for my  $combo (combinations(\@ints, $i)) {

And we dont have [_^] so the total XOR for each subject has to be calculated in yet another loop.

        my $total = 0;

        for my $j (@{$combo}) {
            $total ^= $j;
        }

        $sum += $total;
    }
}

say $sum;

(Full code on Github.)