Perl Weekly Challenge 276.

My solutions (task 1 and task 2 ) to the The Weekly Challenge - 276.

Task 1: Complete Day

Submitted by: Mohammad Sajid Anwar
You are given an array of integers, @hours.

Write a script to return the number of pairs that forms a complete day.

A complete day is defined as a time duration that is an exact multiple of 24 hours.

Example 1
Input: @hours = (12, 12, 30, 24, 24)
Output: 2

Pair 1: (12, 12)
Pair 2: (24, 24)
Example 2
Input: @hours = (72, 48, 24, 5)
Output: 3

Pair 1: (72, 48)
Pair 2: (72, 24)
Pair 3: (48, 24)
Example 3
Input: @hours = (12, 18, 24)
Output: 0

A pair of hours adds to a complete day if their sum is zero modulo 24. I can make an array $N[$h] with the number of hours that equal $h mod 24, all of which pair with (-$h)%24. Thus, the corresponding number of pairs is $N[$h]*$N[-$h%24]. After adding over all possible values of $h=0..23 I would have to divide by 2, to avoid counting every pair twice. Instead, I can choose $h<=12$ so that $(-$h)%24 >=12. There are two exceptions, $h=0 and $h=12, for which $h==(-$h)%24. In those cases I should remove an element pairing with itself, so their contribution to the number of pairs is $N[$h]*($N[$h]-1)/2 instead. The result fits a longish one-liner. Notice that I consider zero hours as a complete, though rather short, day.

Example 1:

perl -E '
$N[$_%24]++for@ARGV;$t+=$N[$_]*$N[(-$_)%24]for 1..11;$t+=$N[$_]*($N[$_]-1)/2for(0,12);say"@ARGV -> $t"
' 12 12 30 24 24

Results:

12 12 30 24 24 -> 2

Example 2:

perl -E '
$N[$_%24]++for@ARGV;$t+=$N[$_]*$N[(-$_)%24]for 1..11;$t+=$N[$_]*($N[$_]-1)/2for(0,12);say"@ARGV -> $t"
' 72 48 24 5

Results:

72 48 24 5 -> 3

Example 3:

perl -E '
$N[$_%24]++for@ARGV;$t+=$N[$_]*$N[(-$_)%24]for 1..11;$t+=$N[$_]*($N[$_]-1)/2for(0,12);say"@ARGV -> $t"
' 12 18 24

Results:

12 18 24 -> 0

The full code is:

 1  # Perl weekly challenge 276
 2  # Task 1:  Complete Day
 3  #
 4  # See https://wlmb.github.io/2024/07/01/PWC276/#task-1-complete-day
 5  use v5.36;
 6  die <<~"FIN" unless @ARGV;
 7      Usage: $0 H1 H2...
 8      to find how many pairs of hours H1, H2... add up to complete days.
 9      FIN
10  my @counts;
11  $counts[$_%24]++ for @ARGV;
12  my $Npairs;
13  $Npairs += ($counts[$_]//0)*($counts[(-$_)%24]//0) for 1..11;
14  $Npairs += ($counts[$_]//0)*(($counts[$_]//0)-1)/2 for(0,12);
15  say "@ARGV -> $Npairs";

Examples:

./ch-1.pl 12 12 30 24 24
./ch-1.pl 72 48 24 5
./ch-1.pl 12 18 24

Results:

12 12 30 24 24 -> 2
72 48 24 5 -> 3
12 18 24 -> 0

Task 2: Maximum Frequency

Submitted by: Mohammad Sajid Anwar
You are given an array of positive integers, @ints.

Write a script to return the total number of elements in the given array which have
the highest frequency.

Example 1
Input: @ints = (1, 2, 2, 4, 1, 5)
Ouput: 4

The maximum frequency is 2.
The elements 1 and 2 has the maximum frequency.
Example 2
Input: @ints = (1, 2, 3, 4, 5)
Ouput: 5

The maximum frequency is 1.
The elements 1, 2, 3, 4 and 5 has the maximum frequency.

I make a hash with the frequencies of each int, find the max, use it to filter the ints and count how many of them have the max frequency. The result fits a oneliner.

Example 1:

perl -MList::AllUtils=max -E '
$N{$_}++ for @ARGV; $m=max values %N; say "@ARGV -> ", $m*grep{$N{$_}==$m}keys %N
' 1 2 2 4 1 5

Results:

1 2 2 4 1 5 -> 4

Example 2:

perl -MList::AllUtils=max -E '
$N{$_}++ for @ARGV; $m=max values %N; say "@ARGV -> ", $m*grep{$N{$_}==$m}keys %N
' 1 2 3 4 5

Results:

1 2 3 4 5 -> 5

The corresponding full code is:

 1  # Perl weekly challenge 276
 2  # Task 2:  Maximum Frequency
 3  #
 4  # See https://wlmb.github.io/2024/07/01/PWC276/#task-2-maximum-frequency
 5  use v5.36;
 6  die <<~"FIN" unless @ARGV;
 7      Usage: $0 N1 N2...
 8      to count how many numbers N1, N2... appear with the maximum frequency.
 9      FIN
10  my %counts;
11  $counts{$_}++ for @ARGV;
12  my $max=max values %N;
13  say "@ARGV -> ", $max*grep{$N{$_}==$max} keys %counts

Examples:

./ch-2.pl 1 2 2 4 1 5
./ch-2.pl 1 2 3 4 5
Written on July 1, 2024