KevKosDev
KevKosDev

Reputation: 849

Prolog search key/value list and output a list of values

I'm once again stuck with a pretty simple Prolog task. I want to define a predicate kv_search/3 that takes a key/value list such as [[a,1],[b,2],[c,3],[d,4],[e,8],[a,9],[b,10]] as a first argument, a key as second and outputs a list of all values with that key in the third argument.

My current approach looks like this:

kv_find([[K,V|_]|Rest], K, Result) :- 
    kv_find(Rest, K, [V|Result]).

kv_find([[Ks,_|_]|Rest], K, Result) :-
    Ks \= K ,
    kv_find(Rest, K, Result).

kv_find([], _, _).

The problem with this solution is however that it just outputs true or false instead of printing the missing parameter.

E.g. the following query result in true instead of my expected result of B=[1, 9]:

kv_find([[a,1],[b,2],[c,3],[d,4],[e,8],[a,9],[b,10]], a, B).

If the key is not present in the list I want to output an empty list.

Upvotes: 1

Views: 467

Answers (1)

coder
coder

Reputation: 12992

Firstly your base case is wrong, you need to write:

kv_find([], _, []).

Since with empty list only an empty output list should succeed.

Then another problem in your solution is that you are writing:

kv_find([[K,V|_]|Rest], K, Result) :- 
    kv_find(Rest, K, [V|Result]).

While you should write something like:

kv_find([[K,V|_]|Rest], K, [V | Result]) :- 
    kv_find(Rest, K, Result).

And the above rule with the wrong base case made your predicate always succeed for any third list.

Moreover with a few changes I would write something like:

kv_find([[K,V]|Rest], K, [V|Result]) :- 
    kv_find(Rest, K, Result).

kv_find([[Ks,_]|Rest], K, Result) :-
    dif(Ks, K) ,
    kv_find(Rest, K, Result).

kv_find([], _, []).

Upvotes: 3

Related Questions