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.
On a second thought, this relation is really all about lists and therefore an excellent candidate for DCGs:
keys_dict_uniquevalues(K,D,UVs) :-
phrase(keys_values(K,D),Vs),
phrase(uniques(Vs),UVs).
keys_values([],_D) --> % no keys no values
[].
keys_values([K|Keys],D) -->
key_values(K,D), % the values for key K
keys_values(Keys,D). % followed by values for other keys
key_values(_K,[]) --> % no values left for key _K
[].
key_values(K,[(K2,V)|Pairs]) --> % values for
{dif(K,K2)}, % different keys are not in the list
key_values(K,Pairs).
key_values(K,[(K,V)|Pairs]) --> % values for en equal key
[V], % are in the list
key_values(K,Pairs).
uniques([]) --> % the empty list has no duplicates
[].
uniques([X|Xs]) -->
[X], % X is in the list
{phrase(list_without(Xs,X),XRs)}, % once
uniques(XRs).
list_without([],_X) --> % no X in the empty list
[].
list_without([X|Xs],X) --> % X is not in the list
list_without(Xs,X).
list_without([Y|Ys],X) -->
[Y], % Y is in the list
{dif(X,Y)}, % if it is different from X
list_without(Ys,X).
I find this version even easier to read than my non-DCG version (see the comments in the code). The interface is the same in both versions so my above queries work one-to-one for this version. The query
?- keys_dict_uniquevalues([a,b],[KV1,KV2],[e]).
also yields the same results just in opposite order.
So far, your problem statement and your subsequent explanations are a bit contradictory. Let's see if this fits.
As the very first, try to describe your problem as a relation and not as a sequence of actions or commands. To better outline this, try to find a name for the relation that does not suggest that something has to be done. Instead, describe each argument one by one. You frowned upon this in a comment, observing that "it's just a name". Of course, just a name. But that's all what a programmer has. Names all over. If every name is just arbitrarily chosen, or even misguiding you will have a very rough time programming.
So what do you have:
A list with elements used as keys
. Note that keys
is a plural. And in Prolog many plurals stand for lists.
Some dictionary, or dict
with (K, V)
elements. Actually, in Prolog, we use more commonly (K-V)
instead and call this a pair
, consequently pairs
would be quite fitting, too. But lets stay with your definition.
A list of values. The list does not possess duplicates. We could call this a list of unique values, or uvalues
.
Now all of it together makes a nice relation:
keys_dict_uvalues(Keys, Dict, UValues)
Before rushing to actual coding, just visualize that you have already written it, and now you want to use it. Or: maybe you will find someone who will write the predicate for you. But how can you be sure that the code is working? So collect some test cases together. Best start with ground queries:
?- keys_dict_uniquevalues([a,c],[(a,aa),(bb,bbb),(a,aa),(c,def)],[aa,def]).
Given that, we could leave out certain parts by introducing variables:
?- keys_dict_uniquevalues([K1,K2],[(a,aa),(bb,bbb),(a,aa),(c,def)],[aa,def]).
How many solutions do you expect here? I think it's only one. Sure? At that point in time such considerations are very valuable.
But now for the coding. I often like a top down approach:
keys_dict_uniquevalues(Ks, KVs, Vsu) :-
keys_dict_values(Ks, KVs, Vs),
list_nub(Vs, Vsu).
keys_dict_values(Ks, KVs, Vs) :-
maplist(list_pmemberv(KVs), Ks, Vs).
list_pmemberv(KVs, K, V) :- % the first fitting K
tmember(k_v_p_t(K,V), KVs).
k_v_p_t(K, V, (Ki, Vi), T) :-
if_(K = Ki, ( Vi = V, T = true ), T = false).
list_nub([], []).
list_nub([E|Es], [E|Gs]) :-
tfilter(dif(E), Es, Fs),
list_nub(Fs, Gs).
Above uses some definitions defined in other examples:
maplist/3
,
if_/3
,
tmember/2
,
tfilter/3
,
(=)/3
,
dif/3
.
Here are some examples, that are rather unusual:
How must a dictionary with two entries look like such that
a
andb
are both mapped toe
?
?- keys_dict_uniquevalues([a,b],[KV1,KV2],[e]).
KV1 = (a,e), KV2 = (b,e)
; KV1 = (b,e), KV2 = (a,e)
; false.
So there are two possibilities.
First, what
check([],_,_).
is supposed to do ? I would drop it.
Then, why do you sort everything ? I would avoid doing useless work...
Last, you need 2 unrelated scan of lists: the first one to get access to keys, the second one to search the value associated to key.
So, your code is not easy to correct without rewriting from scratch. And then consider builtins:
check(Keys,Dict,Values) :-
findall(V, (member(K, Keys), memberchk((K,V),Dict)), Values).
:- import append/3, member/2 from basics.
remove_duplicates([], []).
remove_duplicates([X | Y], Z) :- member(X, Y), !, remove_duplicates(Y, Z).
remove_duplicates([X | Y], [X | Z]) :- remove_duplicates(Y, Z).
hcheck(_, [], []).
hcheck(X, [(X, Y) | L], R) :- !, hcheck(X, L, RR), append([Y], RR, R).
hcheck(X, [_ | L], R) :- hcheck(X, L, R).
check([], _, []).
check([X | Y], L, R) :- hcheck(X, L, RR), check(Y, L, RRR), append(RR, RRR, RRRR), remove_duplicates(RRRR, R).
/********/
/* test */
/********/
[check loaded]
yes
| ?- check([a,c],[(a,aa),(bb,bbb),(a,aa),(c,def)],X).
X = [aa,def];
no
| ?- check([a,b],[(a,c),(a,d),(b,c),(b,e),(c,f)],X).
X = [d,c,e];
no
check/hcheck just form a double loop. check selects elements from the first list while hcheck matches the element to tuples in the second list. Results are simply appended; at the end, duplicates are removed. I am not an expert (just learned Prolog), so I do not know how good this solution is but it seems to work OK.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With