2
votes

I want to count and remove the successive occurrences of the first element in a list.

?- count([1,1,1,2,2,1], N, X, L). 
N = 3, X = 1, L = [2,2,1].               % expected answer

I try this:

count([],0,_,[]).
count([X|T],N,X,L) :-
   !,
   select(X,[X|T],K), 
   L is K,
   count(T,N1,X,L), 
   N is N1+1.
3
What do you expect for count([1,1,1,2], N, X, L)? I don't understand why in your example L is not [1,2,2].false
for count([1,1,1,2], N, X, L) i expect L=[2], N =3, X= 1, that means we have 3 time 1, and in my example we have 3 time 1, and if we remove all of them from the list, we will have L=[2,2,1].parik
What about count([1,2], N, X, L)? Really L = [2]?false
Yes L =[2], X =1, N = 1, and for count([1]), we will have L=[], N=1, X=1parik
your code select(X,[X|T],K ) is rather strange: select/3 is usually called with select(X, Domain, Without_X), that is, X position unknown in Domain list. In the end, it reduces L to T. Nothing other !CapelliC

3 Answers

4
votes

Here's how you could do it using if_/3 and (=)/3:

count([], 0, _, []).
count([E|Es], N, E, L) :-
   skip_(Es, 1,N, E, L).

skip_([], N,N, _, []).
skip_([E|Es], N0,N, X, Xs) :-
   if_(E = X,
       ( N1 is N0+1, skip_(Es,N1,N,X,Xs) ),
       ( N0 = N,     Xs = [E|Es] )).

Sample queries:

?- count([1,1,1,2], N, X, L).
N = 3, X = 1, L = [2].

?- count([1,1,1,2,2,1], N, X, L).
N = 3, X = 1, L = [2,2,1].

?- count([1], N, X, L).
N = X, X = 1, L = [].

?- J = [_,_,_], count(J, N, X, L).
   J = [X, X, X], N = 3, L = []
;  J = [X, X,_A], N = 2, L = [_A]   , dif(_A,X)
;  J = [X,_A,_B], N = 1, L = [_A,_B], dif(_A,X).

Note that count/4 can handle lists containing non-integers just as well:

?- count([a,a,a,b,b,c], N, X, L).
N = 3, X = a, L = [b,b,c].
3
votes
count([], 0, _, []).
count(J, N, X, L) :-
   J = [X|_],
   append(Xs, L, J),
   startsnot_with(L, X),
   maplist(=(X), Xs),
   length(Xs, N).

startsnot_with([], _).
startsnot_with([E|_], X) :-
   dif(E, X).

| ?- J = [_,_,_], count(J, N, X, L).
   J = [X,_A,_B], N = 1, L = [_A,_B], dif(_A,X)
;  J = [X,X,_A],  N = 2, L = [_A], dif(_A,X)
;  J = [X,X,X],   N = 3, L = []
;  false.
0
votes

an eager attempt:

count([X,X|T],N,X,L) :-
    !, count([X|T],M,X,L), N is M+1.
count([X|T],1,X,T) :- !.
count(L,0,_,L).

yields

?- count([1,1,1,2,2,1], N, X, L).
N = 3,
X = 1,
L = [2, 2, 1].

edit since we have an integer domain, an attempt with CLP(FD) - mixed (?) to Prolog eager evaluation

initials_count([X,X|T],N,X,L) :-
    N #= M+1,
    initials_count([X|T],M,X,L).
initials_count([X|T],N,E,T) :-
    N #<==> X #= E.

should be called like

?- once(initials_count([1,1,1,2,2,1], N, X, L)).

(tested with SWI-Prolog)

In GnuProlog, should be

initials_count([X|T],N,E,T) :-
    N #<=> X #= E.

If you want to avoid the problem illustrated in comment by @false, a refinement of the last clause (of first predicate) could be

count(L,0,E,L) :- L == [] ; L == [F|_], F \== E.