Perl Weekly Challenge: Week 271

Challenge 1:

Maximum 1s

You are given a m x n binary matrix.

Write a script to return the row number containing maximum ones, in case of more than one rows then return smallest row number.

Example 1
Input: $matrix = [ [0, 1],
                   [1, 0],
                 ]
Output: 1

Row 1 and Row 2 have the same number of ones, so return row 1.
Example 2
Input: $matrix = [ [0, 0, 0],
                   [1, 0, 1],
                 ]
Output: 2

Row 2 has the maximum ones, so return row 2.
Example 3
Input: $matrix = [ [0, 0],
                   [1, 1],
                   [0, 0],
                 ]
Output: 2

Row 2 have the maximum ones, so return row 2.

There have been a number of matrix-related challenges lately including last week. So we already have code for creating a matrix from command-line argumentes.

my @matrix = @args.map({ [$_.words] });

For this challenge we will also need two additional variables to hold the most 1's found in a row of the matrix so far and the number of that row.

my $maxOnes = 0;
my $maxRow = 0;

Now we go through each row of the matrix noting the row number in $row.

for @matrix.keys -> $row {

We search for 1's in the row with .grep() and count how many we found with .elems().

    my $ones = @matrix[$row].grep({ $_ == 1 }).elems;

If the number of 1's found is greater than our current value of $maxOnes...

    if $ones > $maxOnes {

...we make it the new value of $maxOnes...

        $maxOnes = $ones;

...and make the row number the new value of $maxRow. One thing that tripped me up is that the spec assumes that rows are numbered starting from 1 not 0 as we normally do in computing. So we have to add 1 to $row to get the right number.

        $maxRow = $row + 1;
    }
}

When we have proceessed all the rows, the answer will be in $maxRow so we print it out.

say $maxRow;

(Full code on Github.)

This is the Perl version which works exactly the same as in Raku.

my @matrix = map { [split /\s+/, $_] } @ARGV;
my $maxOnes = 0;
my $maxRow = 0;

for my $row (keys @matrix) {
    my $ones = scalar grep { $_ == 1 } @{$matrix[$row]};
    if ($ones > $maxOnes) {
        $maxOnes = $ones;
        $maxRow = $row + 1;
    }
}

say $maxRow;

(Full code on Github.)

Challenge 2:

Sort by 1 Bits

You are give an array of integers, @ints.

Write a script to sort the integers in ascending order by the number of 1 bits in their binary representation. In case more than one integers have the same number of 1 bits then sort them in ascending order.

Example 1
Input: @ints = (0, 1, 2, 3, 4, 5, 6, 7, 8)
Output: (0, 1, 2, 4, 8, 3, 5, 6, 7)

0 = 0 one bits
1 = 1 one bits
2 = 1 one bits
4 = 1 one bits
8 = 1 one bits
3 = 2 one bits
5 = 2 one bits
6 = 2 one bits
7 = 3 one bits
Example 2
Input: @ints = (1024, 512, 256, 128, 64)
Output: (64, 128, 256, 512, 1024)

All integers in the given array have one 1-bits, so just sort them in ascending order.

We create a hash where the keys are elements of @ints and the values are the number of 1's in each element.

my %ones;

Then for each element...

for @ints -> $i {

...we convert it into binary with base(2) then split it into a list of binary digits with .comb() then find all the 1's in that list with .grep() and count them with .elems(). This value is added to %ones with the element as the key.

    %ones{$i} = $i.base(2).comb.grep({ $_ == 1 }).elems;
}

Finally, we sort the keys of %ones (i.e. the elements of @ints) with the keys with a lower value of 1's coming before the keys with more. In the event of a tie, the element that is numerically smaller comes first. The rest of the line is just for printing out this sorted list in the style of the output in the examples.

say q{(}, %ones.keys.sort({ %ones{$^a} <=> %ones{$^b} || $^a <=> $^b }).join(q{, }), q{)};

(Full code on Github.)

Once again, the Perl solution is almost a direct translation of Raku.

my %ones;

for my $i (@ints) {

With one exception; Perl does not have .base(2) so we use sprintf("%b") instead.

    $ones{$i} = scalar grep { $_ == 1} split //, sprintf("%b", $i);
}

say q{(}, (join q{, }, sort { $ones{$a} <=> $ones{$b} || $a <=> $b } keys %ones), q{)};

(Full code on Github.)