Search code examples
prolog

Count the number of terms that are not atoms in a nested list


I have these facts:

vehicle(car,blue,[wheel,horn,optional(radio)]).
vehicle(motorcycle,blue,[wheel,optional(navigation),horn]).
vehicle(truck,white,[wheel,horn,optional(trailer)]).

I want to count all optional items (all "optional") of all blue vehicles - in this case 2. Right now I have a predicate that creates a nested list with the component lists of all blue vehicles:

countAllOptionalComponents:-
    findall(X,vehicle(_,blue,X),S),
    write(S).

[ [wheel,horn,optional(radio)], [wheel,optional(navigation),horn] ]

My idea was to pass this nested list to another predicate to count all optional components of all "sub-lists", but I'm having trouble. Something like this:

countAllOptionalComponents:-
    findall(X,vehicle(_,blue,X),S),
    countOptComponents(S,N).

countOptComponents([],0).
countOptComponents([X,Y],N):-
[...]

Maybe the approach I'm following doesn't make much sense.


Solution

  • One possible solution would be the following:

    count(C) :-
        findall(X, vehicle(_, blue, X), Ls),
        countOpt(Ls, 0, C).
    
    countOpt([], X, X) :- !.
    countOpt([H|T], C, NewC) :-
        countOpt(T, C, NewC1),
        findall(Opt, member(optional(Opt), H), Opts),
        printOpts(Opts),
        length(Opts, Length),
        NewC is NewC1 + Length, !.
    
    printOpts([]).
    printOpts([H|T]) :-
        print(H),
        nl,
        printOpts(T).
    

    As in your approach, first gather all lists of features (I guess?) for each vehicle and save it in a List of lists called Ls.

    Then select in each sublist of Ls all Optional values (Opt) and add all the lengths of them.

    I also added the predicate to print the results.