Search code examples
listprologtuples

prolog, find list elements in a list of tuples


I'm trying to solve a new program with Prolog, and I'm stuck, and don't know how to continue... I must do a predicate that has 3 arguments, the first is a list of elements, the second one is a list of tuples, and the third one must be a list returned that contains the second element of the tuples, if the first element of the tuple match with an element of the first argument list. It must delete copies also!!

For example,

check([a,c],[(a,aa),(bb,bbb),(a,aa),(c,def)],X).
X = [aa, def] .

As you can see, a and c match on the list of tuples, so return the second element of the tuples.

So it works, BUT if there is more than one tuple that contains a first element that match on the first list, it only will take once, for example:

check([a,b],[(a,c),(a,d),(b,c),(b,e),(c,f)],X).
X = [c] .

It finds a the first time and took c, and b the first time and took c again, but not iterate to find more a or b, the right result should be X=[c,d,e].

So please, I ask you help on how to solve this situation or any clue to solve it...

Here is my code:

check([],_,[]).
check(L,DIC,Xord) :- inter(L,DIC,X), list_to_set(X,Xord).

inter([],_,[]).
inter(L1, DIC, L3) :- 
   L1 = [H|T], 
   DIC = [(DIC1,DIC2)|_], 
   H == DIC1, 
   L3 = [DIC2|L3T], 
   inter(T, DIC, L3T).
inter(L1,[_|DIC],L3) :- inter(L1,DIC,L3).
inter([_|T], DIC, L3) :- inter(T, DIC, L3).

Thanks in advance for your time.


Solution

  • For an easier understandable version I propose the following:

    :- use_module(library(lists)).
    
    keys_dict_uniquevalues(Ks,D,UVs) :-
        keys_dict_values(Ks,D,Vs),              % Vs ... values with duplicates
        list_set(Vs,UVs).                       % UVs ... Vs deduplicated
    
    keys_dict_values([],_D,[]).                 % No keys no values
    keys_dict_values([Key|Keys],D,Vs) :-    
        key_dict_values(Key,D,Matches),         % all Matches for Key
        keys_dict_values(Keys,D,OtherVs),       % Matches for other Keys
        append(Matches,OtherVs,Vs).             % all found values in Vs
    
    key_dict_values(_K,[],[]).                  % no mathes if dictionary empty
    key_dict_values(K,[(K,V)|Pairs],[V|Vs]) :-  % Value is in list if key matches 
        key_dict_values(K,Pairs,Vs).
    key_dict_values(K,[(X,_V)|Pairs],Vs) :-     % Value is not in list
        dif(K,X),                               % if key doesn't match
        key_dict_values(K,Pairs,Vs).
    
    list_set([],[]).                            % empty list contains no duplicates
    list_set([X|Xs],[X|Ys]) :-                  % head of the first list
        subtract(Xs,[X],Zs),                    % doesn't occur in Zs
        list_set(Zs,Ys).
    

    If you want so write a program without the use of library(lists) you have to replace the goal append/3 in keys_dict_values/3 and the goal subtract/3 in list_set/2. In the below example by lists_appended/3 and list_x_removed/3:

    keys_dict_uniquevalues(Ks,D,UVs) :-
        keys_dict_values(Ks,D,Vs),
        list_set(Vs,UVs).
    
    keys_dict_values([],_D,[]).
    keys_dict_values([Key|Keys],D,Vs) :-
        key_dict_values(Key,D,Matches),
        keys_dict_values(Keys,D,OtherVs),
        lists_appended(Matches,OtherVs,Vs).
    
    key_dict_values(_K,[],[]).
    key_dict_values(K,[(K,V)|Pairs],[V|Vs]) :-
        key_dict_values(K,Pairs,Vs).
    key_dict_values(K,[(X,_V)|Pairs],Vs) :-
        dif(K,X),
        key_dict_values(K,Pairs,Vs).
    
    lists_appended([],L,L).
    lists_appended([X|Xs],Ys,[X|Zs]) :-
        lists_appended(Xs,Ys,Zs).
    
    list_set([],[]).
    list_set([X|Xs],[X|Ys]) :-
        list_x_removed(Xs,X,Zs),
        list_set(Zs,Ys).
    
    list_x_removed([],_X,[]).
    list_x_removed([X|Xs],X,Ys) :-
        list_x_removed(Xs,X,Ys).
    list_x_removed([X|Xs],Z,[X|Ys]) :-
        dif(X,Z),
        list_x_removed(Xs,Z,Ys).
    

    The queries given in the above exmaple work for both versions:

    ?- keys_dict_uniquevalues([a,c],[(a,aa),(bb,bbb),(a,aa),(c,def)],X).
    X = [aa,def] ? ;
    no
    ?- keys_dict_uniquevalues([a,b],[(a,c),(a,d),(b,c),(b,e),(c,f)],L).
    L = [c,d,e] ? ;
    no
    

    The counterexample provided by @false fails for both versions as expected:

    ?- keys_dict_uniquevalues([a,b],[(a,c),(a,d),(b,c),(b,e),(c,f)],[c,c]).
    no
    

    The unusual usage as suggested by @false:

       ?- keys_dict_uniquevalues([a,b],[KV1,KV2],[e]).
    KV1 = KV2 = (a,e) ? ;
    KV1 = (a,e),
    KV2 = (b,e) ? ;
    KV1 = (a,e),
    KV2 = (_A,_B),
    dif(b,_A),
    dif(a,_A) ? ;
    KV1 = (b,e),
    KV2 = (a,e) ? ;
    KV1 = (_A,_B),
    KV2 = (a,e),
    dif(b,_A),
    dif(a,_A) ? ;
    KV1 = KV2 = (b,e) ? ;
    KV1 = (b,e),
    KV2 = (_A,_B),
    dif(b,_A),
    dif(a,_A) ? ;
    KV1 = (_A,_B),
    KV2 = (b,e),
    dif(b,_A),
    dif(a,_A) ? ;
    no