Perl Weekly Challenge: Week 269
Challenge 1:
Bitwise OR
You are given an array of positive integers,
@ints
.Write a script to find out if it is possible to select two or more elements of the given array such that the bitwise OR of the selected elements has atlest one trailing zero in its binary representation.
Example 1
Input: @ints = (1, 2, 3, 4, 5)
Output: true
Say, we pick 2 and 4, their bitwise OR is 6. The binary representation of 6 is 110.
Return true since we have one trailing zero.
Example 2
Input: @ints = (2, 3, 8, 16)
Output: true
Say, we pick 2 and 8, thier bitwise OR is 10. The binary representation of 10 is 1010.
Return true since we have one trailing zero.
Example 3
Input: @ints = (1, 2, 5, 7, 9)
Output: false
Raku does it again and solves this task in one line.
say @*ARGS.combinations(2 .. @*ARGS.elems).grep({ ([+|] @$_).base(2).ends-with(0) }).elems > 0
We use the command-line arguments as input and then get all combinations of 2 or more elements with .combinations()
. Then using
.grep()
we go through each combination and OR all its elements with the [+|]
operator. This gives a decimal result so we convert
it to binary digits with .base(2)
. Testing if the binary representation ends in 0 is easy with .ends-with(0)
. If the number of
suitable elements found by .grep()
is greater than 0, say
prints out True
or otherwise False
.
For Perl, we have to provide our own implementations of .combinations()
and [+|]
. The former has appeared in many previous challenges but the latter is new. The function below remedies the lack.
bitwiseOR()
takes as input a reference to a list for no other reason than that combinations()
returns each combination as
a list reference. I will change that at some point.
sub bitwiseOR($listref) {
Especially because I immediately convert it back to a list anyway.
my @list = @{$listref};
First $result
is initialized with the first element of the list which is then removed.
my $result = shift @list;
Then every other element in @list
is ORed with $result
.
for my $elem (@list) {
$result |= $elem;
}
Finally, $result
is returned.
return $result;
}
Now we can (mostly) follow the same algorithm as Raku.
my @ints = @ARGV;
Because my version of combinations()
doesn't support ranges like in Raku, a double for loop is needed.
for my $i (2 .. scalar @ints) {
for my $combo (combinations(\@ints, $i)) {
if ((split //, sprintf("%b", bitwiseOR($combo)))[-1] == '0') {
We don't need all OR combinations ending in 0; just one is enough for us to be able ro determine truth or falsefood.
So if we find one, we print true
and stop processing early. (Unlike Raku.)
say 'true';
exit(0);
}
}
}
If we didn't find any suitable combinations, we print false
.
say 'false';
Challenge 2:
Distribute Elements
You are given an array of distinct integers,
@ints
.Write a script to distribute the elements as described below:
1) Put the 1st element of the given array to a new array @arr1.
2) Put the 2nd element of the given array to a new array @arr2.
Once you have one element in each arrays,
@arr1
and@arr2
, then follow the rule below:
If the last element of the array @arr1 is greater than the last
element of the array @arr2 then add the first element of the
given array to @arr1 otherwise to the array @arr2.
When done distribution, return the concatenated arrays.
@arr1
and@arr2
.
Example 1
Input: @ints = (2, 1, 3, 4, 5)
Output: (2, 3, 4, 5, 1)
1st operation:
Add 1 to @arr1 = (2)
2nd operation:
Add 2 to @arr2 = (1)
3rd operation:
Now the last element of @arr1 is greater than the last element
of @arr2, add 3 to @arr1 = (2, 3).
4th operation:
Again the last element of @arr1 is greate than the last element
of @arr2, add 4 to @arr1 = (2, 3, 4)
5th operation:
Finally, the last element of @arr1 is again greater than the last
element of @arr2, add 5 to @arr1 = (2, 3, 4, 5)
Mow we have two arrays:
@arr1 = (2, 3, 4, 5)
@arr2 = (1)
Concatenate the two arrays and return the final array: (2, 3, 4, 5, 1).
Example 2
Input: @ints = (3, 2, 4)
Output: (3, 4, 2)
1st operation:
Add 1 to @arr1 = (3)
2nd operation:
Add 2 to @arr2 = (2)
3rd operation:
Now the last element of @arr1 is greater than the last element
of @arr2, add 4 to @arr1 = (3, 4).
Mow we have two arrays:
@arr1 = (3, 4)
@arr2 = (2)
Concatenate the two arrays and return the final array: (3, 4, 2).
Example 3
Input: @ints = (5, 4, 3 ,8)
Output: (5, 3, 4, 8)
1st operation:
Add 1 to @arr1 = (5)
2nd operation:
Add 2 to @arr2 = (4)
3rd operation:
Now the last element of @arr1 is greater than the last element
of @arr2, add 3 to @arr1 = (5, 3).
4th operation:
Again the last element of @arr2 is greate than the last element
of @arr1, add 8 to @arr2 = (4, 8)
Mow we have two arrays:
@arr1 = (5, 3)
@arr2 = (4, 8)
Concatenate the two arrays and return the final array: (5, 3, 4, 8).
The spec is sufficiently clear that we can translate it into Raku almost verbatim.
Put the 1st element of the given array to a new array @arr1.
my @arr1 = @ints.shift;
Put the 2nd element of the given array to a new array @arr2.
my @arr2 = @ints.shift;
If the last element of the array @arr1
is greater than the last element of the array @arr2
then add the first element of the given array to @arr1
otherwise to the array @arr2
.
(Note: I used .keys()
here to traverse through @ints
by index. But in hindsight, that seems pointless. I could
just as easily have traversed through the elements themselves.)
for @ints.keys -> $k {
(Also for readabilities' sake, I should have written this as an if-else
statement rather than use the ternary operator.)
@arr1[*-1] > @arr2[*-1] ?? @arr1.push(@ints[$k]) !! @arr2.push(@ints[$k]);
}
Return the concatenated arrays. @arr1
and @arr2
.
(The additional code is merely to make the output pretty.)
say q{(}, @arr1.push(| @arr2).join(q{, }), q{)};
This is the Perl version. For once, we didn't need any additional code to mimic Raku features. It shares the same faults as the Raku version.
my @ints = @ARGV;
my @arr1 = shift @ints;
my @arr2 = shift @ints;
for my $k (keys @ints) {
if ($arr1[-1] > $arr2[-1]) {
push @arr1, $ints[$k];
} else {
push @arr2, $ints[$k];
}
}
push @arr1, @arr2;
say q{(}, (join q{, }, @arr1), q{)};