with Raku

This is my response to The Weekly Challenge #244.

You are given an array of integers.

Write a script to calculate the number of integers smaller than the integer at each index.

Example 1:

File: count-smaller
Write a script to calculate the number of integers smaller than the integer at each index.

Example 1:

Input: @int = (8, 1, 2, 2, 3)
Output: (4, 0, 1, 1, 3)
For index = 0, count of elements less 8 is 4.
For index = 1, count of elements less 1 is 0.
For index = 2, count of elements less 2 is 1.
For index = 3, count of elements less 2 is 1.
For index = 4, count of elements less 3 is 3.

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

Example 3:
Input: @int = (2, 2, 2)
Output: (0, 0, 0)

#! /usr/bin/env raku
unit sub MAIN (*@int where @int.elems > 0 && all(@int) ~~ Int, # [1]
:v(:$verbose));
my $index = 0;
my @output; # [2]
for @int -> $int # [3]
{
my $count = @int.grep( * < $int).elems; # [4]
say ": For index = { $index++ }, count of elements less $int is $count."
if $verbose;
@output.push: $count; # [5]
}
say "(" ~ @output.join(", ") ~ ")"; # [6]

[1] At least one element, all of which must be integers.

[2] The result will end up here.

[3] Iterate over the input values. Note that the index value is used by verbose mode only.

[4] Get the number of values (`.elems`

) in the
array that are less than the current one, using `grep`

.

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

.

[5] Add the count (from [4]) to the output array.

[6] Pretty print the result.

Running it:

$ ./count-smaller 8 1 2 2 3
(4, 0, 1, 1, 3)
$ ./count-smaller 6 5 4 8
(2, 1, 0, 3)
$ ./count-smaller 2 2 2
(0, 0, 0)

Looking good.

With verbose mode:

$ ./count-smaller -v 8 1 2 2 3
: For index = 0, count of elements less 8 is 4.
: For index = 1, count of elements less 1 is 0.
: For index = 2, count of elements less 2 is 1.
: For index = 3, count of elements less 2 is 1.
: For index = 4, count of elements less 3 is 3.
(4, 0, 1, 1, 3)
$ ./count-smaller -v 6 5 4 8
: For index = 0, count of elements less 6 is 2.
: For index = 1, count of elements less 5 is 1.
: For index = 2, count of elements less 4 is 0.
: For index = 3, count of elements less 8 is 3.
(2, 1, 0, 3)
$ ./count-smaller -v 2 2 2
: For index = 0, count of elements less 2 is 0.
: For index = 1, count of elements less 2 is 0.
: For index = 2, count of elements less 2 is 0.
(0, 0, 0)

Let us have a go at a oneliner version, using `map`

:

say "(" ~ @int.map({ @int.grep({ $_ < $_ }).elems }).join(", ") ~ ")";
## #1 #2 #2 #1

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

.

The idea is that the grepped values (#2) should be lower than the current
limit/value (#1). But this will not work, as `$_`

will refer to
the grepped one only - and not to values from different scopes.

We can remedy that by saving the outermost `$_`

(the one from
`map`

) in a variable:

#! /usr/bin/env raku
unit sub MAIN (*@int where @int.elems > 0 && all(@int) ~~ Int);
say "(" ~ @int.map({ my $map = $_; @int.grep({ $_ < $map }).elems }).join(", ") ~ ")";

Running this gives the expected result:

$ ./count-smaller-oneliner-my 2 2 2
(0, 0, 0)
$ ./count-smaller-oneliner-my 8 1 2 2 3
(4, 0, 1, 1, 3)
$ ./count-smaller-oneliner-my 6 5 4 8
(2, 1, 0, 3)

But... it is not elegant.

We can use a `*`

(whatever star) (and get rid of the closure brackets)
for one of the original `$_`

instances instead, thus removing the
conflict:

#! /usr/bin/env raku
unit sub MAIN (*@int where @int.elems > 0 && all(@int) ~~ Int);
say "(" ~ @int.map({ @int.grep( * < $_ ).elems }).join(", ") ~ ")";

Running it gives the expected result, again:

$ ./count-smaller-oneliner 8 1 2 2 3
(4, 0, 1, 1, 3)
$ ./count-smaller-oneliner 6 5 4 8
(2, 1, 0, 3)
$ ./count-smaller-oneliner 2 2 2
(0, 0, 0)

You are given an array of integers representing the strength.

Write a script to return the sum of the powers of all possible combinations; power is defined as the square of the largest number in a sequence, multiplied by the smallest.

Example:

File: group-hero
Write a script to return the sum of the powers of all possible combinations; power is defined as the square of the largest number in a sequence, multiplied by the smallest.

Example:

Input: @nums = (2, 1, 4)
Output: 141
Group 1: (2) => square(max(2)) * min(2) => 4 * 2 => 8
Group 2: (1) => square(max(1)) * min(1) => 1 * 1 => 1
Group 3: (4) => square(max(4)) * min(4) => 16 * 4 => 64
Group 4: (2,1) => square(max(2,1)) * min(2,1) => 4 * 1 => 4
Group 5: (2,4) => square(max(2,4)) * min(2,4) => 16 * 2 => 32
Group 6: (1,4) => square(max(1,4)) * min(1,4) => 16 * 1 => 16
Group 7: (2,1,4) => square(max(2,1,4)) * min(2,1,4) => 16 * 1 => 16
Sum: 8 + 1 + 64 + 4 + 32 + 16 + 16 => 141

#! /usr/bin/env raku
unit sub MAIN (*@nums where @nums.elems > 0 && all(@nums) ~~ Int, # [1]
:v(:$verbose));
my $group = 0; # [2]
my $total = 0; # [3]
for @nums.combinations(1..Inf) -> @candidate # [4]
{
my $max = @candidate.max; # [5]
my $min = @candidate.min; # [6]
my $sum = $max ** 2 * $min; # [7]
$total += $sum; # [8]
say ": Group { ++$group }: ({ @candidate.join(",") }) => \
square(max({ @candidate.join(",") })) * min({ @candidate.join(",") }) \
=> { $max ** 2 } * $min => $sum" if $verbose;
}
say $total; # [9]

[1] As in «Count Smaller».

[2] Used by verbose mode only.

[3] The answer (grand total) is built up here.

[4] Get all the combinations of the input, which is exactly what we are after. Well, not absolutely all. The first one is an empty list, so we use an array slice to start at the second one (with index 1).

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

.

[5] Compute the maximum,

[6] the minimum,

[7] and the sum (using the formulae given in the challenge).

[8] Add this sum to the grand total.

[9] Print the grand total.

Running it:

$ ./group-hero 2 1 4
141

Looking good.

With verbose mode:

$ ./group-hero -v 2 1 4
: Group 1: (2) => square(max(2)) * min(2) => 4 * 2 => 8
: Group 2: (1) => square(max(1)) * min(1) => 1 * 1 => 1
: Group 3: (4) => square(max(4)) * min(4) => 16 * 4 => 64
: Group 4: (2,1) => square(max(2,1)) * min(2,1) => 4 * 1 => 4
: Group 5: (2,4) => square(max(2,4)) * min(2,4) => 16 * 2 => 32
: Group 6: (1,4) => square(max(1,4)) * min(1,4) => 16 * 1 => 16
: Group 7: (2,1,4) => square(max(2,1,4)) * min(2,1,4) => 16 * 1 => 16
141

And that's it.