RabbitFarm

2023-01-08

Prime the Gaps!

The examples used here are from the weekly challenge problem statement and demonstrate the working solution.

Part 1

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.

Solution


use v5.36;
sub largest_gap{
    my(@numbers) = @_;
    my $gap = -1;
    map{ $gap = $numbers[$_] - $numbers[$_ - 1] if $numbers[$_] - $numbers[$_ - 1] > $gap } 1 .. @numbers - 1;  
    return $gap;
}

sub gap_pairs{
    my(@numbers) = @_;
    return 0 if @numbers < 2; 
    my $gap = largest_gap(@numbers);
    my $gap_count;
    map { $gap_count++ if $numbers[$_] - $numbers[$_ - 1] == $gap } 1 .. @numbers - 1;  
    return $gap_count;

}

MAIN:{
    say gap_pairs(3);    
    say gap_pairs(2, 5, 8, 1);    
}

Sample Run


$ perl perl/ch-1.pl 
0
2

Notes

Probably these two subroutines could be combined into one without too much trouble, but it still seems cleaner to me this way.

  1. Do an initial pass over the list to determine the largest gap.

  2. Perform a second pass over the list and count up all pairs which have the maximum gap.

An interesting issue came up. I've been trying to avoid the use of a map in a void context. This is just due to the general principal to use map as a function and use its return value rather than rely on side effects.

As part of this reformative effort I have been doing more with for in a postfix position. I discovered this when working this problem:

{say $_ if $_ % 2 == 0} for 0 .. 9 will not work. Perl gets confused by the postfix if within the block, apparently.

But there is a work around! Add do and all is well.

do {say $_ if $_ % 2 == 0} for 0 .. 9

Of course the equivalent map works just fine as you'd expect map {say $_ if $_ % 2 == 0} 0 .. 9)

E. Choroba pointed out this is due to postfix for being a statement modifier which doesn't know what to do with blocks. But why does do fix this? I am still unclear on why that is. Even with the do it's still a block! Apparently perl will view it as a statement, for the purposes of the postfix for?

UPDATE: Turns out that the do {} construct qualifies as a Simple Statement. From the perldoc: Note that there are operators like eval {}, sub {}, and do {} that look like compound statements, but aren't--they're just TERMs in an expression--and thus need an explicit termination when used as the last item in a statement.

Part 2

You are given an integer $n > 0. Write a script to print the count of primes less than $n.

Solution


use v5.36;
use Math::Primality q/is_prime/;

sub prime_count{
    return 0 + grep { is_prime $_ } 2 .. $_[0] - 1;  
}

MAIN:{
    say prime_count(10);  
    say prime_count(15);  
    say prime_count(1);  
    say prime_count(25);  
}

Sample Run


$ perl perl/ch-2.pl
4
6
0
9

Notes

The Math::Primality module makes this quite easy! In fact, I am not sure there is that much to elaborate on. Check primality using is_prime() and we're done!

References

Challenge 198

posted at: 19:30 by: Adam Russell | path: /perl | permanent link to this entry

The Weekly Challenge 198 (Prolog Solutions)

The examples used here are from the weekly challenge problem statement and demonstrate the working solution.

Part 1

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.

Solution


largest_gap(Numbers, LargestGap):-
    largest_gap(Numbers, -1, LargestGap).  
largest_gap([], LargestGap, LargestGap).  
largest_gap([_|[]], LargestGap, LargestGap).  
largest_gap([A, B|Numbers], Gap, LargestGap):-
    G is B - A,
    (G > Gap, largest_gap([B|Numbers], G, LargestGap));
    largest_gap([B|Numbers], Gap, LargestGap).

gap_pairs(Numbers, GapPairs):-
    length(Numbers, L),
    L =< 2,
    GapPairs = 0.
gap_pairs(Numbers, GapPairs):-
    length(Numbers, L),
    L > 2, 
    largest_gap(Numbers, LargestGap),
    gap_pairs(Numbers, LargestGap, 0, GapPairs).
gap_pairs([], _, GapPairs, GapPairs).
gap_pairs([_|[]], _, GapPairs, GapPairs).
gap_pairs([A, B|Numbers], LargestGap, Pairs, GapPairs):-
    LargestGap #= B - A,
    succ(Pairs, P),
    gap_pairs([B|Numbers], LargestGap, P, GapPairs).
gap_pairs([A, B|Numbers], LargestGap, Pairs, GapPairs):-
    LargestGap #\= B - A,
    gap_pairs([B|Numbers], LargestGap, Pairs, GapPairs). 

Sample Run


$ gprolog --consult-file prolog/ch-1.p
| ?- gap_pairs([3], Pairs).

Pairs = 0 ? 

(1 ms) yes
| ?- gap_pairs([2, 5, 8, 1], Pairs).

Pairs = 2 ? 

yes
| ?- 

Notes

At first glance this code may look more complex than it really is. All we are doing is , first, computing the largest gap between any two adjacent numbers. Then, second, seeing which pairs have exactly this gap.

Part 2

You are given an integer $n > 0. Write a script to print the count of primes less than $n.

Solution


primes_under_n(N, NumberPrimes):-
    findall(Prime, (between(2, N, I), fd_prime(I), Prime = I), Primes),
    length(Primes, NumberPrimes).  

Sample Run


$ gprolog --consult-file prolog/ch-2.p
| ?- primes_under_n(10, Primes).

Primes = 4

yes
| ?- primes_under_n(15, Primes).

Primes = 6

yes
| ?- primes_under_n(1, Primes). 

Primes = 0

yes
| ?- primes_under_n(25, Primes).

Primes = 9

yes

Notes

This solution is short and sweet! No reason or the writeup to be longer than the code itself, right?

References

Challenge 198

posted at: 13:29 by: Adam Russell | path: /prolog | permanent link to this entry