29 August 2025 | Challenge 336 |
Finally Equal
Task 1: Equal Group
Submitted by: Mohammad Sajid Anwar
You are given an array of integers.
Write a script to return true if the given array can be divided into one or more groups: each group must be of the same size as the others, with at least two members, and with all members having the same value.
Example 1
Input: @ints = (1,1,2,2,2,2)
Output: true
Groups: (1,1), (2,2), (2,2)
Example 2
Input: @ints = (1,1,1,2,2,2,3,3)
Output: false
Groups: (1,1,1), (2,2,2), (3,3)
Example 3
Input: @ints = (5,5,5,5,5,5,7,7,7,7,7,7)
Output: true
Groups: (5,5,5,5,5,5), (7,7,7,7,7,7)
Example 4
Input: @ints = (1,2,3,4)
Output: false
Example 5
Input: @ints = (8,8,9,9,10,10,11,11)
Output: true
Groups: (8,8), (9,9), (10,10), (11,11)
Solution
Take the frequency of each item in the array and check if these have a common factor larger than one. This approach is not limited to numbers.
use strict;
use warnings;
use List::MoreUtils 'frequency';
use List::Util 'pairmap';
use Math::Prime::Util 'gcd';
sub equal_group {
1 < gcd pairmap {$b} frequency @_;
}
See the full solution to task 1.
Task 2: Final Score
Submitted by: Mohammad Sajid Anwar
You are given an array of scores by a team.
Write a script to find the total score of the given team. The score can be any integer, +
, C
or D
. The +
adds the sum of previous two scores. The score C
invalidates the previous score. The score D
will double the previous score.
Example 1
Input: @scores = ("5","2","C","D","+")
Output: 30
Round 1: 5
Round 2: 5 + 2
Round 3: 5 (invalidate the previous score 2)
Round 4: 5 + 10 (double the previous score 5)
Round 5: 5 + 10 + 15 (sum of previous two scores)
Total Scores: 30
Example 2
Input: @scores = ("5","-2","4","C","D","9","+","+")
Output: 27
Round 1: 5
Round 2: 5 + (-2)
Round 3: 5 + (-2) + 4
Round 4: 5 + (-2) (invalidate the previous score 4)
Round 5: 5 + (-2) + (-4) (double the previous score -2)
Round 6: 5 + (-2) + (-4) + 9
Round 7: 5 + (-2) + (-4) + 9 + 5 (sum of previous two scores)
Round 8: 5 + (-2) + (-4) + 9 + 5 + 14 (sum of previous two scores)
Total Scores: 27
Example 3
Input: @scores = ("7","D","D","C","+","3")
Output: 45
Round 1: 7
Round 2: 7 + 14 (double the previous score 7)
Round 3: 7 + 14 + 28 (double the previous score 14)
Round 4: 7 + 14 (invalidate the previous score 28)
Round 5: 7 + 14 + 21 (sum of previous two scores)
Round 6: 7 + 14 + 21 + 3
Total Scores: 45
Example 4
Input: @scores = ("-5","-10","+","D","C","+")
Output: -55
Round 1: (-5)
Round 2: (-5) + (-10)
Round 3: (-5) + (-10) + (-15) (sum of previous two scores)
Round 4: (-5) + (-10) + (-15) + (-30) (double the previous score -15)
Round 5: (-5) + (-10) + (-15) (invalidate the previous score -30)
Round 6: (-5) + (-10) + (-15) + (-25) (sum of previous two scores)
Total Scores: -55
Example 5
Input: @scores = ("3","6","+","D","C","8","+","D","-2","C","+")
Output: 128
Round 1: 3
Round 2: 3 + 6
Round 3: 3 + 6 + 9 (sum of previous two scores)
Round 4: 3 + 6 + 9 + 18 (double the previous score 9)
Round 5: 3 + 6 + 9 (invalidate the previous score 18)
Round 6: 3 + 6 + 9 + 8
Round 7: 3 + 6 + 9 + 8 + 17 (sum of previous two scores)
Round 8: 3 + 6 + 9 + 8 + 17 + 34 (double the previous score 17)
Round 9: 3 + 6 + 9 + 8 + 17 + 34 + (-2)
Round 10: 3 + 6 + 9 + 8 + 17 + 34 (invalidate the previous score -2)
Round 11: 3 + 6 + 9 + 8 + 17 + 34 + 51 (sum of previous two scores)
Total Scores: 128
Solution
Embedding the logic in a tiny class.
use strict;
use warnings;
use experimental 'signatures';
package Score;
use List::Util ();
sub new ($class) {
bless [], $class;
}
sub total ($self) {
List::Util::sum0 @$self;
}
sub apply ($self, @scores) {
for (@scores) {
push(@$self, $_), next if /^-?\d+$/;
pop(@$self), next if /^C$/;
push(@$self, 2 * ($self->[-1] // 0)), next if /^D$/;
push(@$self, ($self->[-2] // 0) + ($self->[-1] // 0)), next if /^\+$/;
die "score invalid: $_";
}
$self;
}
There are only one constructor and two methods apply
and total
.
apply
can be used to apply any number of operations on a stack and - as it returns the object itself - may be chained.
And there is total
that provides the required final score.
Actually the final state for all of $x
, $y
and $z
is the same in this snippet:
my $x = Score->new;
$x->apply(3);
$x->apply(2);
$x->apply('+');
my $y = Score->new->apply(3)->apply(2)->apply('+');
my $z = Score->new->apply(qw(3 2 +));
With this class the solution reduces to:
package main;
sub final_score {
Score->new->apply(@_)->total;
}
See the full solution to task 2.
If you have a question about this post or if you like to comment on it, feel free to open an issue in my github repository.