RabbitFarm

2025-05-04

The Weekly Challenge 319 (Prolog Solutions)

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

Part 1: Word Count

You are given a list of words containing alphabetic characters only. Write a script to return the count of words either starting with a vowel or ending with a vowel.

Our solution will be pretty short, contained in just a single file that has the following structure.

"ch-1.p" 1


vowels 2
start_end_vowel 3
word count 4

We’re going to be using character codes for this. For convenience let’s declare are vowels this way.

vowels 2 ⟩≡


vowel(97). % a
vowel(101). % e
vowel(105). % i
vowel(111). % o
vowel(117). % u

Fragment referenced in 1.

We’ll use a small predicate, later to be called from maplist, to check if a word starts or ends with a vowel.

start_end_vowel 3 ⟩≡


start_end_vowel(Word, StartsEnds):-
((nth(1, Word, FirstLetter),
vowel(FirstLetter));
(last(Word, LastLetter),
vowel(LastLetter))),
StartsEnds = true.
start_end_vowel(_, -1).

Fragment referenced in 1.

We’ll need a predicate to tie everything together, that’s what this next one does.

word count 4 ⟩≡


word_count(Words, Count):-
maplist(start_end_vowel, Words, StartsEndsAll),
delete(StartsEndsAll, -1, StartsEnds),
length(StartsEnds, Count).

Fragment referenced in 1.

Sample Run
$ gprolog --consult-file prolog/ch-1.p 
| ?- word_count(["unicode", "xml", "raku", "perl"], Count). 
 
Count = 2 ? 
 
yes 
| ?- word_count(["the", "weekly", "challenge"], Count). 
 
Count = 2 ? 
 
yes 
| ?- word_count(["perl", "python", "postgres"], Count). 
 
Count = 0 
 
yes 
| ?-
    

Part 2: Minimum Common

You are given two arrays of integers. Write a script to return the minimum integer common to both arrays. If none found return -1.

As in the first part, our solution will be pretty short, contained in just a single file.

"ch-2.p" 5


minimum common 7

To check for common elements is easy in Prolog. First we subtract/3 all elements of one list from the other. That will give us the unique elements. Then we’ll delete the unique elements from one of the original lists to get all common elements. After that min_list/2 determines the result.

subtract lists to determine common elemets 6 ⟩≡


subtract(List1, List2, Difference1),
subtract(List2, List1, Difference2),
append(Difference1, Difference2, Differences),
subtract(List1, Differences, Common),

Fragment referenced in 7.

Defines: Common 7.

minimum_common/3 is the main (and only) predicate we define

minimum common 7 ⟩≡


minimum_common(List1, List2, MinimumCommon):-
subtract lists to determine common elemets 6
length(Common, L),
L >= 1,
min_list(Common, MinimumCommon).
minimum_common(_, _, -1).

Fragment referenced in 5.

Uses: Common 6.

Sample Run
$ gprolog --consult-file prolog/ch-2.p 
| ?- minimum_common([1, 2, 3, 4], [3, 4, 5, 6], MinimumCommon). 
 
MinimumCommon = 3 ? 
 
yes 
| ?- minimum_common([1, 2, 3], [2, 4], MinimumCommon). 
 
MinimumCommon = 2 ? 
 
yes 
| ?- minimum_common([1, 2, 3, 4], [5, 6, 7, 8], MinimumCommon). 
 
MinimumCommon = -1 
 
yes 
| ?-
    

References

The Weekly Challenge 319
Generated Code

posted at: 14:47 by: Adam Russell | path: /prolog | permanent link to this entry

In the Count of Common

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

Part 1: Word Count

You are given a list of words containing alphabetic characters only. Write a script to return the count of words either starting with a vowel or ending with a vowel.

Our solution will be pretty short, contained in just a single file that has the following structure.

"ch-1.pl" 1


preamble 2
count the words that begin or end with a vowel 4
main 3

The preamble is just whatever we need to include. Here we aren’t using anything special, just specifying the latest Perl version.

preamble 2 ⟩≡


use v5.40;

Fragment referenced in 1, 6.

the main section is just some basic tests.

main 3 ⟩≡


MAIN:{
say word_count qw/unicode xml raku perl/;
say word_count qw/the weekly challenge/;
say word_count qw/perl python postgres/;
}

Fragment referenced in 1.

All the work is done in the count section which contains a single small subroutine.

count the words that begin or end with a vowel 4 ⟩≡


sub word_count{
return 0 + grep { start/end vowel check 5 } @_;
}

Fragment referenced in 1.

For clarity we’ll break that vowel check into it’s own code section. It’s not too hard. We use the beginning and ending anchors (^, $) to see if there is a character class match at the beginning or end of the word.

start/end vowel check 5 ⟩≡


$_ =~ m/^[aeiou]/ || $_ =~ m/.*[aeiou]$/

Fragment referenced in 4.

Sample Run
$ perl perl/ch-1.pl 
2 
2 
0
    

Part 2: Minimum Common

You are given two arrays of integers. Write a script to return the minimum integer common to both arrays. If none found return -1.

As in the first part, our solution will be pretty short, contained in just a single file that has the following structure.

(The preamble is going to be the same as before, we don’t need anything extra for this problem either.)

The main section just drives a few tests.

The subroutine that gets the bulk of the solution started is in this section.

"ch-2.pl" 6


preamble 2
sub minimum_common{
my($u, $v) = @_;
find common elements 7
return $minimum;
}
main 8

Defines: $u 7, $v 7.

Uses: $minimum 7.

The real work is done in this section. We determine the unique elements by creating two separate hashes and then, using the keys to each hash, count the number of common elements. We then sort the common elements, if there are any, and set $minimum to be the smallest one.

find common elements 7 ⟩≡


my %h = ();
my %h_u = map {$_ => undef} @{$u};
my %h_v = map {$_ => undef} @{$v};
my $minimum = -1;
do{
$h{$_}++;
} for (keys %h_u, keys %h_v);
my @common = grep {$h{$_} > 1} keys %h;
if(0 < @common){
$minimum = (sort {$a <=> $b} @common)[0];
}

Fragment referenced in 6.

Defines: $minimum 6.

Uses: $u 6, $v 6.

main 8 ⟩≡


MAIN:{
say minimum_common [1, 2, 3, 4], [3, 4, 5, 6];
say minimum_common [1, 2, 3], [2, 4];
say minimum_common [1, 2, 3, 4], [5, 6, 7, 8];
}

Fragment referenced in 6.

Sample Run
$ perl perl/ch-2.pl 
3 
2 
-1
    

References

The Weekly Challenge 319
Generated Code

posted at: 12:25 by: Adam Russell | path: /perl | permanent link to this entry