Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method that counts the number of occurs in one list in Prolog

Tags:

prolog

I have to write a method that can count the number of occurrences of one list from another list given. For example:

?-reps([a,b,c,a,b,c],[a,b,c],0,R). 
R = 2 ? ;
no

I was trying to code it:

incr(X, X1) :-
   X1 is X+1.

reps([],[],C,D):-
   incr(C,D).
reps(_,[],C,D):-
   incr(C,D),
   !.
reps([X|A],[X|B],C,D):-
   reps(A,B,C,D),
   reps(A,B,C,D).

My main problem is that, I can compare the first time, but the second time my "comparation list" is now empty and I can't compare the rest of the list. Is there a way to make a global variable that can store the "comparation list" to call it after?

like image 652
Alvaro Sánchez Avatar asked Jan 25 '23 08:01

Alvaro Sánchez


1 Answers

As pointed out in comments in my other attempt at a pure solution that also supports generalized queries, the use of findall/3 is questionable as to the purity. This answer works without findall/3. It assumes that the pattern to look for is a non-empty list, otherwise the result is inf.

reps/3 checks if P is a pattern in L, and if so, counts its occurrences using reps/4. A special case is with the pattern count 0. To avoid negating pattern, the predicate nopattern checks if the pattern is contained exactly one in a list where it is appended first.

pattern([A],[A]).
pattern([H|T],P) :- append(P,_,[H|T]);pattern(T,P).

noPattern(L,P) :- append(P,L,PL),reps(PL,P,0,1).

startNoMatch([],[_]):- true.
startNoMatch(_,[]):- false.
startNoMatch([X1|T1],[X2|T2]) :- dif(X1,X2); startNoMatch(T1,T2).

reps(L,P,C,C) :- length(L,L1), length(P,L2), L1 < L2.
reps(L,P,C,D):- append(P,R,L),C1 is C+1, reps(R,P,C1,D).
reps([H|T],P,C,D):- startNoMatch([H|T],P),reps(T,P,C,D).

reps(_,[],inf).
reps(L,P,0) :- P=[_|_],noPattern(L,P).
reps(L,P,C) :- P=[_|_],pattern(L,P),reps(L,P,0,C),C>0.
like image 92
jf_ Avatar answered Mar 16 '23 06:03

jf_