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

Viewed 70

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.

2 Answers

If you are already using findall() and you know that there can be more than one goal in the middle of findall by wrapping it in () then you can put another findall in there:

countAllOptionalComponents(OptionCount) :-
    findall(CarOptions,
        (vehicle(_, blue, CarAllItems),
         findall(O, member(optional(O), CarAllItems), CarOptions)
        ), AllOptionsNested),
    append(AllOptionsNested, AllOptions),
    write(AllOptions),
    length(AllOptions, OptionCount).

append/2 flattens nested lists, append([[horn], [radio,aircon]], [horn,radio,aircon]).

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.

Related