简体   繁体   中英

return elements from list of lists - prolog

I have a list of lists that contain titles and scores like : [ [ 'title1',100 ],[ 'title2',200 ],...] . I have to make a predicate that returns the title if I have a certain score. find_title(Score,List,ListOfTitles) . Also some scores may be the same that's why I am trying to store it in a List..in case there is more than one titles with the same score.

I tried this :

return_title(Score,List,[H|T]):-
    return_title(Score,List,T),
    member([X,Score],List),
    H=X.

But it doesn't work..any ideas on another implementation?

Think declaratively: Just consider what the predicate should describe. It's a relation between a score , a list of titles and scores and a list of titles matching the score in the first argument. I find it helpful to find descriptive names for predicates, where one can see at once which argument is what. So why not go with something like score_list_titles/3. Then I think about what cases there are to cover in my description. For this relation I see three cases:

score_list_titles(_S,[],[]).                 % 1: if list is empty titles is empty
score_list_titles(S,[[T,S]|TSs],[T|Ts]) :-   % 2: if score matches S, T is in titles
   score_list_titles(S,TSs,Ts).              % relation must hold for the tails as well
score_list_titles(S,[[T,X]|TSs],Ts) :-       % 3: if score
   dif(S,X),                                 % doesn't match S, T is not in titles
   score_list_titles(S,TSs,Ts).              % relation must hold for the tails as well

Querying this predicate produces the following results: Which titles have a score of 100, 200 and 300 respectively?

   ?- score_list_titles(100,[['title1',100],['title2',200],['title3',100]],T).
T = [title1,title3] ? ;
no

   ?- score_list_titles(200,[['title1',100],['title2',200],['title3',100]],T).
T = [title2] ? ;
no

   ?- score_list_titles(300,[['title1',100],['title2',200],['title3',100]],T).
T = []

What titles are there for what scores?

   ?- score_list_titles(S,[['title1',100],['title2',200],['title3',100]],T).
S = 100,
T = [title1,title3] ? ;
S = 200,
T = [title2] ? ;
T = [],
dif(S,100),
dif(S,200),
dif(S,100)

You can even express this relation more compactly by using if_/3 :

score_list_titles(_S,[],[]).
score_list_titles(S,[[T,X]|TSs],TL) :-   % if S=X: T is in titles
   if_(S=X, TL=[T|Ts], TL=Ts),           % otherwise it isn't
   score_list_titles(S,TSs,Ts).          % relation must hold for the tails as well

This way the predicate doesn't even leave an unnecessary choice-point open in the case where the first two arguments are ground (= contain no free variables). You can see that if you compare the below queries with the above ones: In the above version of score_list_titles/3 I had to enter ; after the single answer, to get the feedback that there are no further solutions.

   ?- score_list_titles(100,[['title1',100],['title2',200],['title3',100]],T).
T = [title1,title3]

   ?- score_list_titles(200,[['title1',100],['title2',200],['title3',100]],T).
T = [title2]

you're doing more complex than needed:

return_title(Score,List,X):-
    member([X,Score],List).

then you can use Prolog 'all solutions' builtins, like findall/3, or REPL backtracking (hit ';' after an answer).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM