Perl Weekly Challenge 198.
My solutions (task 1 and task 2 ) to the The Weekly Challenge - 198.
Task 1: Max Gap
Submitted by: Mohammad S Anwar
You are given a list of integers, @list.
Write a script to find the total pairs in the sorted list where 2 consecutive elements
has the max gap. If the list contains less then 2 elements then return 0.
Example 1
Input: @list = (2,5,8,1)
Output: 2
Since the sorted list (1,2,5,8) has 2 such pairs (2,5) and (5,8)
Example 2
Input: @list = (3)
Output: 0
I sort the input, build an array of gaps, find the maximum and count how many gaps coincide with it. This fits a one liner:
perl -MList::Util=max -E '
@l=sort {$a<=>$b} @ARGV; $m=max @g=map{$l[$_]-$l[$_-1]} 1..@l-1; say 0+grep{$_==$m} @g;
' 2 5 8 1
perl -MList::Util=max -E '
@l=sort {$a<=>$b} @ARGV; $m=max @g=map{$l[$_]-$l[$_-1]} 1..@l-1; say 0+grep{$_==$m} @g;
' 3
Results:
2
0
The disadvantage of this procedure is that I go twice through the array of gaps, once to find the maximum and once to count how many gaps are equal to it. I can avoid one pass by storing the counts in a hash. I can also calculate the maximum on the fly.
perl -E '@l=sort {$a<=>$b} @ARGV; for(1..@l-1){++$c{$g=$l[$_]-$l[$_-1]}; $m=$g if $g>$m}; say $c{$m}||0;' 2 5 8 1
perl -E '@l=sort {$a<=>$b} @ARGV; for(1..@l-1){++$c{$g=$l[$_]-$l[$_-1]}; $m=$g if $g>$m}; say $c{$m}||0;' 3
Results:
2
0
The full code is
1 # Perl weekly challenge 198
2 # Task 1: Max Gap
3 #
4 # See https://wlmb.github.io/2023/01/02/PWC198/#task-1-max-gap
5 use v5.36;
6 my @sorted=sort {$a<=>$b} @ARGV;
7 my %count;
8 my $max;
9 for(1..@sorted-1){
10 ++$count{my $gap=$sorted[$_]-$sorted[$_-1]};
11 $max=$gap if !defined $max || $gap>$max;
12 };
13 say join " ", @ARGV, "->", $count{$max}||0
Examples:
./ch-1.pl 2 5 8 1
./ch-1.pl 3
Results:
2 5 8 1 -> 2
3 -> 0
Task 2: Prime Count
Submitted by: Mohammad S Anwar
You are given an integer $n > 0.
Write a script to print the count of primes less than $n.
Example 1
Input: $n = 10
Output: 4 as in there are 4 primes less than 10 are 2, 3, 5 ,7.
Example 2
Input: $n = 15
Output: 6
Example 3
Input: $n = 1
Output: 0
Example 4
Input: $n = 25
Output: 9
I could calculate the number of primes below a certain number by building an Eratosthenes sieve and counting how many elements survive. This is easily done using the Perl Data language:
perl -MPDL -MPDL::NiceSlice -E 'for(@ARGV){say("1 -> 0"), next unless $_>=2; $s=ones($_); $s(0:1).=0;
$s($_**2:-1:$_).=0 for(2..sqrt($_-1)); say "$_ -> ", $s->sumover}' 10 15 1 25
Results:
10 -> 4
15 -> 6
1 -> 0
25 -> 9
Notice that the cases $n=1
(or less) require special treatment to
avoid indexing problems.
An alternative is to just use Math::Prime::Util
. There is a subtlety as $n
may itself be prime, and the challenge statement uses less, not less
than. Thus, I have to subtract 1 before calling prime_count
.
perl -MMath::Prime::Util=prime_count -E 'say "$_ -> ", prime_count($_-1) for @ARGV' 10 15 1 25
Results:
10 -> 4
15 -> 6
1 -> 0
25 -> 9
The full code is as simple
1 # Perl weekly challenge 198
2 # Task 2: Prime Count
3 #
4 # See https://wlmb.github.io/2023/01/02/PWC198/#task-2-prime-count
5 use v5.36;
6 use Math::Prime::Util qw(prime_count);
7 say(<<~"FIN"), exit unless @ARGV;
8 Usage: $0 N1 [N2...]
9 to fin the number of primes below N1, N2...
10 FIN
11 say "$_ -> ", prime_count($_-1) for @ARGV;
Example:
./ch-2.pl 10 15 1 25
Results:
10 -> 4
15 -> 6
1 -> 0
25 -> 9