There is a way (well, infinite ways) to solve this with prolog builtins, such as sort/2
, findall/3
, member/2
, include/3
and length/2
:
?- List=[3,2,6,2,2,1,4,2,2,2,2,4,1,2,3,2,2,4,2,3,2],
sort(List, Uniq), % sort removing duplicate elements
findall([Freq, X], (
member(X, Uniq), % for each unique element X
include(=(X), List, XX), %
length(XX, Freq) % count how many times appears in List
), Freqs),
sort(Freqs, SFreqs), % sort (by frequency)
last(SFreqs, [Freq, MostCommon]), % last pair is the most common
length(List, ListLen),
Freq > ListLen/2. % is frequency greater than half list length?
List = [3, 2, 6, 2, 2, 1, 4, 2, 2|...],
Uniq = [1, 2, 3, 4, 6],
Freqs = [[2, 1], [12, 2], [3, 3], [3, 4], [1, 6]],
SFreqs = [[1, 6], [2, 1], [3, 3], [3, 4], [12, 2]],
Freq = 12,
MostCommon = 2,
ListLen = 21.
Depending on what constraints the instructor did put for solving the excercise, you may need to implement one or more of these builtins by yourself.
Another way, more efficient, would be to use msort/2
and then create a run-length encoding of the sorted list, then sort it again, and pick the element representing the most commonly occurring element. Right now I can't figure out how to do run-length encoding without defining auxiliary recursive predicates, so here it is:
count_repeated([Elem|Xs], Elem, Count, Ys) :-
count_repeated(Xs, Elem, Count1, Ys), Count is Count1+1.
count_repeated([AnotherElem|Ys], Elem, 0, [AnotherElem|Ys]) :-
Elem \= AnotherElem.
count_repeated([], _, 0, []).
rle([X|Xs], [[C,X]|Ys]) :-
count_repeated([X|Xs], X, C, Zs),
rle(Zs, Ys).
rle([], []).
then, getting the most common element can be done with:
?- List=[3,2,6,2,2,1,4,2,2,2,2,4,1,2,3,2,2,4,2,3,2],
msort(List, SList),
rle(SList, RLE),
sort(RLE, SRLE),
last(SRLE, [Freq, MostCommon]),
length(List, ListLen),
Freq > ListLen/2.
List = [3, 2, 6, 2, 2, 1, 4, 2, 2|...],
SList = [1, 1, 2, 2, 2, 2, 2, 2, 2|...],
RLE = [[2, 1], [12, 2], [3, 3], [3, 4], [1, 6]],
SRLE = [[1, 6], [2, 1], [3, 3], [3, 4], [12, 2]],
Freq = 12,
MostCommon = 2,
ListLen = 21.