theWhiteKnight
theWhiteKnight

Reputation: 61

Prolog: counting atoms in a list

I'm trying to count atoms in a list. I can count all the atoms but I can't count a specific atom. I know there's something wrong with my code but I'm not sure how to fix it.

This works to count all the atoms in a list (the E (element) is irrelevant here):

count_atoms(_,[],0).
count_atoms(E,[H|T],R):- number(H), count_atoms(E,T,R1),R is R1,!.
count_atoms(E,[H|T],R):- var(H), count_atoms(E,T,R1),R is R1,!.
count_atoms(E,[H|T],R):- atom(H), count_atoms(E,T,R1),R is R1+1,!.

But this doesn't work to find the E (element) in the list:

count_atoms(_,[],0).
count_atoms(E,[H|T],R):- number(H), count_atoms(E,T,R1),R is R1,!.
count_atoms(E,[H|T],R):- var(H), count_atoms(E,T,R1),R is R1,!.
count_atoms(E,[H|T],R):- atom(H), E==H, count_atoms(E,T,R1),R is R1+1,!.

The result I get each time is just false.
Does anyone know what I'm doing wrong?

Upvotes: 2

Views: 430

Answers (4)

tiffi
tiffi

Reputation: 683

The question has already been answered by @DuDa - ypu forgot to take care of the case of a list member that is an atom different from whatever E is bound to. In addition, you didn't take care of the case that H is a structure.

I would only like to add that it makes things easier, if you do not try to enumerate all cases, but work with a catch-all clause, for expl:

count_atoms(_,[],0).
count_atoms(E,[E|T],R):- atom(E),count_atoms(E,T,R1),R is R1+1,!.
count_atoms(E,[_|T],R):- count_atoms(E,T,R). % catch-all

Even with the addition of the answer above, the proof of a question will still fail with lists that contain structures like [a,b,c,f(d),e], whereas it works with a catch-all clause.

For example, Prolog will answer the question ?- count_atoms(a,[a,b,c,f(d),e],R). with no even with the addition above, but with R = 1. when using a catch-all clause.

Upvotes: 1

slago
slago

Reputation: 5509

In SWI-Prolog, another possible solution is:

count_atoms(Atom, List, Count) :-
     aggregate_all(count,
                   (member(Item, List),
                    atom(Item),
                    Item = Atom),
                   Count).

Here are some examples:

?- count_atoms(a, [a,b,a,X,c,f(d),a,Y,b,a], Count).
Count = 4.

?- count_atoms(b, [a,b,a,X,c,f(d),a,Y,b,a], Count).
Count = 2.

?- count_atoms(c, [a,b,a,X,c,f(d),a,Y,b,a], Count).
Count = 1.

?- count_atoms(d, [a,b,a,X,c,f(d),a,Y,b,a], Count).
Count = 0.

Upvotes: 0

Duda
Duda

Reputation: 3736

You did not state what happens if H is an atom but not equal to E.

Add this:

count_atoms(E,[H|T],R):- atom(H), E\==H, count_atoms(E,T,R),!.

Output:

?- count_atoms(a,[a,b,a,c],R).
R = 2.

Also there is a lot of improvement possible.

Upvotes: 1

Reema Q Khan
Reema Q Khan

Reputation: 878

An alternate approach:

count(H,List,Count):-   
    count1(H,List,0,Count).

count1(_, [], Count, Count). %base case
count1(H,[K|T],CountA,Count):-  %Count atom in List
    H=K,
    CountB is CountA+1,
    count1(H,T,CountB,Count).
count1(H,[K|T],CountA,Count):- %Don't count when atom not in list
    H\=K,
    count1(H,T,CountA,Count).

Example:

?- count(a,[a,a,a],Count).
Count = 3
false

?- count(b,[a,a,b,n,n,a],Count).
Count = 1
false

?- count(n,[a,a,b,n,n,a],Count).
Count = 2
false

?- count(c,[a,a,b,n,n,a],Count).
Count = 0
false

Upvotes: 0

Related Questions