2

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.
repeat
  • 18,496
  • 4
  • 54
  • 166
parik
  • 2,313
  • 12
  • 39
  • 67
  • 1
    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 Dec 30 '15 at 23:07
  • 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 Dec 30 '15 at 23:12
  • 1
    What about `count([1,2], N, X, L)`? Really `L = [2]`? – false Dec 30 '15 at 23:20
  • Yes L =[2], X =1, N = 1, and for count([1]), we will have L=[], N=1, X=1 – parik Dec 30 '15 at 23:21
  • 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 Dec 31 '15 at 08:49

3 Answers3

4

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].
Community
  • 1
  • 1
repeat
  • 18,496
  • 4
  • 54
  • 166
3
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.
false
  • 10,264
  • 13
  • 101
  • 209
0

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.
CapelliC
  • 59,646
  • 5
  • 47
  • 90
  • Both definitions are incorrectly succeeding for the following cases: `?- count([a],0,a,L).` and `?- initials_count([1],0,2,[]).` – false Dec 31 '15 at 19:58