with Raku

This is my response to The Weekly Challenge #271.

You are given a

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:

`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.

File: maximum-ones

#! /usr/bin/env raku
unit sub MAIN ($string = "0 0 | 1 1 | 0 0", :v(:$verbose)); # [1]
my $matrix = $string.split("|")>>.words>>.Int>>.Array; # [2]
die "The rows must have the same size" unless [==] $matrix>>.elems; # [3]
die "Must contain 0s and 1s only" unless all($matrix[*;*]) ~~ one(0,1); # [4]
my @sum = $matrix>>.sum.pairs # [5]
.sort({ $^b.value <=> $^a.value || $^a.key <=> $^b.key }); # [5a]
say ": index => sums: { @sum.raku } (zero based index)" if $verbose;
say 1 + @sum[0].key; # [6]

[1] Note the default matrix, and the syntax for specifying it as a string.

[2] Convert the matrix-as-a-string thingy to a two dimentional array.

[3] Ensure that all the rows have the same length.

[4] Retrieve all the values and ensure that all of them are oither 0 or 1.

[5] Apply `sum`

on each row to reduce the rows to a single
value. Then turn the sums into an array of Pair objects with `pairs`

. The
key is the index from the former array, and the value is the former value
itself. Then we sort this array, on the value part (highest first), and then
if the values are equal on the key (row number; lowest first).

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

.

[6] Get the first result, and add 1 to the index as the challenge uses 1 for the first row (and Raku is zero based).

Running it:

$ ./maximum-ones "0 1 | 1 0"
1
$ ./maximum-ones "0 0 0 | 1 0 1"
2
$ ./maximum-ones
2

Looking good.

With verbose mode:

$ ./maximum-ones -v "0 1 | 1 0"
: index => sums: [0 => 1, 1 => 1] (zero based index)
1
$ ./maximum-ones -v "0 0 0 | 1 0 1"
: index => sums: [1 => 2, 0 => 0] (zero based index)
2
$ ./maximum-ones -v
: index => sums: [1 => 2, 0 => 0, 2 => 0] (zero based index)
2

You are give an array of integers,

Write a script to sort the integers in

Example 1:

`@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.

The challenge does not say anything about duplicate values, so I have chosen to allow it.

File: sort-by-1-bits#! /usr/bin/env raku
unit sub MAIN (*@ints where @ints.elems > 0, :v(:$verbose)); # [1]
die "Non-negative integers only" unless all(@ints) ~~ UInt; # [2]
my @binary = @ints.map({ $_.fmt('%b').comb.sum => $_ }) # [3]
.sort({$^a.key <=> $^b.key || $^a.value <=> $^b.value }); # [3a]
@binary.map({ say ": { $_.value } = { $_.key } one bits" }) if $verbose;
say '(', @binary.map( *.value ).join(", "), ')'; # [4]

[1] Ensure at least on element.

[2] They must all be unsigned integers.

[3] {ID:fmt}} The `map`

part converts the value to binary (with `fmt`

),
them we split that number into individual characters (with `comb`

), and
add them all together with `sum`

- thus giving the number of 1 bits.
That is on the left hand side of the Pair (created with the `=>`

thing).
The value itself is the value of the pair. Then we sort the pairs.

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

.

[4] Use `map`

to convert the pair objects into the value part, and pritty
print the result.

Running it:

$ ./sort-by-1-bits 0 1 2 3 4 5 6 7 8
(0, 1, 2, 4, 8, 3, 5, 6, 7)
$ ./sort-by-1-bits 1024 512 256 128 64
(64, 128, 256, 512, 1024)

Looking good.

With verbose mode:

$ ./sort-by-1-bits -v 0 1 2 3 4 5 6 7 8
: 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
(0, 1, 2, 4, 8, 3, 5, 6, 7)
$ ./sort-by-1-bits -v 1024 512 256 128 64
: 64 = 1 one bits
: 128 = 1 one bits
: 256 = 1 one bits
: 512 = 1 one bits
: 1024 = 1 one bits
(64, 128, 256, 512, 1024)

And that's it.