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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With