This is my response to the Perl Weekly Challenge #163.
@n
.
Input: @n = (1, 2, 3)
Output: 3
Since (1 & 2) + (2 & 3) + (1 & 3) => 0 + 2 + 1 => 3.
Example 2:
Input: @n = (2, 3, 4)
Output: 2
Since (2 & 3) + (2 & 4) + (3 & 4) => 2 + 0 + 0 => 2.
I do believe that «Positive numbers» should be read as «Postive integers».
File: sbo
#! /usr/bin/env raku
unit sub MAIN (*@values where @values.elems > 0
&& all(@values) ~~ /^<[1..9]><[0..9]>*$/, # [1]
:v(:$verbose));
if $verbose
{
say ": Combinations: { @values.combinations(2)
.map({ "(" ~ $_[0] ~ "," ~ $_[1] ~ ")" } ) }";
say ": Mapped to: { @values.combinations(2).map({ $_[0] ~& $_[1]} ) }";
}
say @values.combinations(2).map({ $_[0] ~& $_[1]} ).sum; # [2]
[1] Note the regex to ensure a postivie integer, without a leading zero.
[2]
We use combinations(2)
to get all the unique combinations
of length 2. Then we use map
to bitwise AND (the ~&
operator)
the two values together, and finaly we use .sum
to add the values together.
See
docs.raku.org/routine/combinations
for more information about combinations
.
See
docs.raku.org/language/operators#index-entry-Numeric_bitwise_AND_operator
for more information about the numeric bitwise AND operator ~&
.
Running it:
$ ./sbo 1 2 3
3
$ ./sbo 2 3 4
2
With verbose mode:
$ ./sbo -v 1 2 3
: Combinations: (1,2) (1,3) (2,3)
: Mapped to: 0 1 2
3
$ ./sbo -v 2 3 4
: Combinations: (2,3) (2,4) (3,4)
: Mapped to: 2 0 0
2
all
,
sum
and combinations
.
File: sbo-perl
#! /usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Getopt::Long;
use Perl6::Junction 'all';
use List::Util qw(sum);
use Algorithm::Combinatorics qw(combinations);
my $verbose = 0;
GetOptions("verbose" => \$verbose);
my @values = @ARGV;
die "Please specify a list of positve integers" unless @values;
die "Integers only" unless qr/^[1-9][0-9]*$/ == all(@values);
my $sum = 0;
for my $pair (combinations(\@values, 2))
{
my $and = $pair->[0] & $pair->[1];
$sum += $and;
say ": Pair: $pair->[0], $pair->[1] (-> $and)" if $verbose;
}
say $sum;
Running it gives the same result as the Raku version, except for a slightly different verbose output:
$ ./sbo-perl -v 1 2 3
: Pair: 1, 2 (-> 0)
: Pair: 1, 3 (-> 1)
: Pair: 2, 3 (-> 2)
3
$ ./sbo-perl -v 2 3 4
: Pair: 2, 3 (-> 2)
: Pair: 2, 4 (-> 0)
: Pair: 3, 4 (-> 0)
2
@n
.
Input: @n = (1, 2, 3, 4, 5)
Output: 42
1 2 3 4 5
2 5 9 14
5 14 28
14 42
42
The nth Row starts with the second element of the (n-1)th row. The
following element is sum of all elements except first element of
previous row. You stop once you have just one element in the row.
Example 2:
Input: @n = (1, 3, 5, 7, 9)
Output: 70
1 3 5 7 9
3 8 15 24
8 23 47
23 70
70
I do believe that «Positive numbers» should be read as «Postive integers», as in the first part of the challenge.
File: summations
#! /usr/bin/env raku
unit sub MAIN (*@values where @values.elems > 0
&& all(@values) ~~ /^<[1..9]><[0..9]>*$/,
:v(:$verbose));
while @values.elems > 1 # [1]
{
say ": @values[]" if $verbose;
@values = next-row(@values); # [2]
}
say @values[0]; # [3]
sub next-row (@values)
{
my @new;
for (1 .. @values.elems -1) -> $index # [4]
{
@new.push: @values[1..$index].sum; # [5]
}
return @new; # [6]
}
[1] As long as there are more than 1 element in the array,
[2] Transform the array to the next version (with one element less).
[3] Print the remaining element.
[4] For each index in the incoming array (except zero),
[5] Get the sum of all the elements from index 1 to the current index, and add that to the new list.
[6] Return the new list.
Running it:
$ ./summations 1 2 3 4 5
42
$ ./summations 1 3 5 7 9
70
With verbose mode:
$ ./summations -v 1 2 3 4 5
: 1 2 3 4 5
: 2 5 9 14
: 5 14 28
: 14 42
42
$ ./summations -v 1 3 5 7 9
: 1 3 5 7 9
: 3 8 15 24
: 8 23 47
: 23 70
70
#! /usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Getopt::Long;
use Perl6::Junction 'all';
use List::Util qw(sum);
use feature 'signatures';
no warnings qw(experimental::signatures);
my $verbose = 0;
GetOptions("verbose" => \$verbose);
my @values = @ARGV;
die "Please specify a list of positve integers" unless @values;
die "Integers only" unless qr/^[1-9][0-9]*$/ == all(@values);
while (@values > 1)
{
say ": @values" if $verbose;
@values = next_row(@values);
}
say $values[0];
sub next_row (@values)
{
my @new;
for my $index (1 .. @values -1)
{
push(@new, sum(@values[1..$index]));
}
return @new;
}
Running it gives the same result as the Raku version:
$ ./summations-perl 1 2 3 4 5
42
$ ./summations-perl -v 1 3 5 7 9
70
With verbose mode:
$ ./summations-perl -v 1 2 3 4 5
: 1 2 3 4 5
: 2 5 9 14
: 5 14 28
: 14 42
42
$ ./summations-perl -v 1 3 5 7 9
: 1 3 5 7 9
: 3 8 15 24
: 8 23 47
: 23 70
70
And that's it.