Prolog lists difference - list

I'm trying to make program in prolog that will do something like this:
diffSet([a,b,c,d], [a,b,e,f], X).
X = [c,d,e,f]
I wrote this:
diffSet([], _, []).
diffSet([H|T1],Set,Z):- member(Set, H), !, diffSet(T1,Set,Z).
diffSet([H|T], Set, [H|Set2]):- diffSet(T,Set,Set2).
But in that way I can only get elements from the first list. How can I extract the elements from the second one?
#edit:
member is checking if H is in Set
member([H|_], H).
member([_|T], H):- member(T, H).

There is a builtin that remove elements from the list:
diffSet([], X, X).
diffSet([H|T1],Set,Z):-
member(H, Set), % NOTE: arguments swapped!
!, delete(T1, H, T2), % avoid duplicates in first list
delete(Set, H, Set2), % remove duplicates in second list
diffSet(T2, Set2, Z).
diffSet([H|T], Set, [H|Set2]) :-
diffSet(T,Set,Set2).

Or using only built-ins. if you wanted to just get the job done:
notcommon(L1, L2, Result) :-
intersection(L1, L2, Intersec),
append(L1, L2, AllItems),
subtract(AllItems, Intersec, Result).
?- notcommon([a,b,c,d], [a,b,e,f], X).
X = [c, d, e, f].

Deliberately avoiding the built ins for this that #chac mentions, this is an inelegant way that does the job.
notcommon([], _, []).
notcommon([H1|T1], L2, [H1|Diffs]) :-
not(member(H1, L2)),
notcommon(T1, L2, Diffs).
notcommon([_|T1], L2, Diffs) :-
notcommon(T1, L2, Diffs).
alldiffs(L1, L2, AllDiffs) :-
notcommon(L1, L2, SetOne),
notcommon(L2, L1, SetTwo),
append(SetOne, SetTwo, AllDiffs).
? alldiffs([a,b,c,d], [a,b,e,f], X).
X = [c, d, e, f] .

Related

Prolog Lists from List Predicate

I am trying to make a code in which the input is a list with lists and non-lists within it and the output is a list with the lists from the first input. So, for example input listsFromList([2,3,6,[a,g],2,3,[c,d]],X). The output would be X = [[a,g],[c,d]]. I am trying to do it with an accumulator.
So I made this code:
listsFromList([],A) :- A.
listsFromList([H|SOURCEs],A) :-
is_list(H),
append([A],H,A),
listsFromList(SOURCEs,A).
listsFromList([H|SOURCEs],A) :-
\+ is_list(H),
listsFromList(SOURCEs,A).
It does not work if I put more than one list in the first list and also it gives a wrong output when I put one list in it. Can anyone help?
You need to modify few things. Here a solution with the same number of arguments:
listsFromList([],[]).
listsFromList([H|SOURCEs],[H|A1]) :-
is_list(H),
listsFromList(SOURCEs,A1).
listsFromList([H|SOURCEs],A) :-
\+ is_list(H),
listsFromList(SOURCEs,A).
?- listsFromList([2,3,6,[a,g],2,3,[c,d]],X).
X = [[a, g], [c, d]];
false
If you want to use append/3, you could add an accumulator list (so increase the arity form 2 to 3), but this is unnecessary, or swap the position of append/3. Furthermore, you can add a cut (!) to avoid the false solution.
Solution wiht accumulator:
listsFromList([],L,L).
listsFromList([H|SOURCEs],LIn,LO) :-
is_list(H),
append([H],LIn,L),
listsFromList(SOURCEs,L,LO).
listsFromList([H|SOURCEs],L,LO) :-
\+ is_list(H),
listsFromList(SOURCEs,L,LO).
?- listsFromList([2,3,6,[a,g],2,3,[c,d]],[],X).
X = [[c, d], [a, g]]
false
If you want to use append/2 with arity 2 of the main predicate, use:
listsFromList([],[]).
listsFromList([H|SOURCEs],L) :-
is_list(H),
listsFromList(SOURCEs,L1),
append([H],L1,L).
listsFromList([H|SOURCEs],A) :-
\+ is_list(H),
listsFromList(SOURCEs,A).
?- listsFromList([2,3,6,[a,g],2,3,[c,d]],X).
X = [[a, g], [c, d]]
false
If you want to be super fancy and super short, you can solve your problem (assuming you are running SWI Prolog) with one line:
?- include(is_list,[2,3,6,[a,g],2,3,[c,d]],X).
X = [[a, g], [c, d]]

Prolog: remove member of list with non-instantiated values

I want remove all appearences of an element on a list, similar to this, but in my case, the list may have non-instantiated variables. For example:
delMember(z, [A,B,A,z], L).
L = [A, B, A];
false.
and
delMember(A, [A, B, A, z], L).
L = [B,z];
false.
I tried defining delMember as the following:
delMember(_, [], []).
delMember(X, [X|Xs], Y) :- delMember(X, Xs, Y).
delMember(X, [T|Xs], [T|Y]) :- X \== T, delMember(X, Xs, Y).
With this definition, the last result I get is correct but it's still trying to instantiate the variables before that.
?- delMember(A, [A,B,A,z], R).
A = B, B = z,
R = [] ;
A = B,
R = [z] ;
A = z,
R = [B] ;
R = [B, z] ;
any ideas???
If you look at your second predicate clause:
delMember(X, [X|Xs], Y) :- delMember(X, Xs, Y).
Unification is occurring with the X in the first and second arguments. This leads to the results you are observing when you do your query. You need to apply the same operator as you did in your third clause. So your complete predicate (with some slightly changed variable names to be more conventional) would look like:
delMember(_, [], []).
delMember(X, [X1|Xs], Ys) :- X == X1, delMember(X, Xs, Ys).
delMember(X, [X1|Xs], [X1|Ys]) :- X \== X1, delMember(X, Xs, Ys).

Can anyone help me in writing a prolog program for deleting a list?

Ex: If I have been given two list [1,4,3,2,5,6] and [1,2,3] the final list should be [4,5,6].
i.e., Del([1,4,3,2,5,6], [1,2,3], Result).
----should output Result=[4,5,6].
I have tried something like this:
delete1(A, [A|B], B).
delete1(A, [B, C|D], [B|E]) :- delete1(A, [C|D], E).
But the output I'm getting is by deleting the element being passed as an parameter and not a list.
Output:
delete1(a,[a,b,c,d],Res).
(0) Call: delete1(a,[a,b,c,d],_h210) ?
(0) Exit: delete1(a,[a,b,c,d],[b,c,d]) ?
Res = [b,c,d]
Can anyone please help me how to go about this ?
Pure and simple: Use meta-predicate tfilter/3 in tandem with list_nonmember_t/3!
Like we did with memberd_t/3, we define list_nonmember_t/3 based on if_/3 and (=)/3:
list_nonmember_t([],_,true).
list_nonmember_t([E|Es],X,T) :-
if_(E=X, T=false, list_nonmember_t(Es,X,T)).
Let's put it together!
?- tfilter(list_nonmember_t([1,2,3]), [1,4,3,2,5,6], Xs).
Xs = [4,5,6]. % succeeds deterministically
del1([], _, []).
del1([A|L], B, R) :- member(A, B), del1(L, B, R).
del1([A|L], B, [A|R]) :- not(member(A,B)), del1(L, B, R).
So your delete1 is a good start, it allows to delete single element from the list, but it is not handling all of the cases. For example the lists that are not containing the element to be deleted.
So the right one would be :
delete1(_, [], []).
delete1(A, [A|B], B).
delete1(A, [C|B], [C|E]) :- delete1(A, B, E).
and then using this, you can define your del1 by applying delete1 recursively on the whole list:
del1([], _, []).
del1(L, [], L).
del1(L, [H|T], R) :-
delete1(H, L, R1),
del1(R1, T, R).
And of course you can use builtin list predicates as stated in the other answer.

Prolog. Sum of the elements of two lists of different length

Please help me!
I need to find sum of the elements of two lists of different length.
It should look like:
?-p([1,2,3],[1,2,3,9],L),write(L),nl.
L = [2,4,6,9].
p([],_,[]).
p(_,[],[]).
p([H1|T1],[H2|T2],[H|T]):-H is H1 + H2,p(T1,T2,T).
?-p([1,2,3],[1,2,3],L),write(L),nl.
So I've got some troubles with different length of lists. I don't know how to do it.
Thanks for your help! Tanya.
I prefer shorter, deterministic code, where possible:
p([X|Xs], [Y|Ys], [Z|Zs]) :-
Z is X + Y,
!, p(Xs, Ys, Zs).
p([], Ys, Ys) :- !.
p(Xs, [], Xs).
This should work:
p([], [], []).
p([], [H2|T2], [L|Ls]) :-
L = H2,
p([], T2, Ls).
p([H1|T1], [], [L|Ls]) :-
L = H1,
p(T1, [], Ls).
p([H1|T1], [H2|T2], [L|Ls]) :-
L is H1 + H2,
p(T1, T2, Ls).
Explanation:
As long as there are elements in both lists, they get added and 'prepended' to L. Whenever there is 1 list empty, it will just 'prepend' them to L without adding it. When both are empty, the recursivity stops.

Prolog substitution

How can I replace a list with another list that contain the variable to be replaced. for example
rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p]
the x to z and z doesn't change after it has been replaced.
so far I did only the one without the list
rep([], _, []).
rep(L1, H1=H2, L2) :-
rep(L1, H1, H2, L2).
rep([],_,_,[]).
rep([H|T], X1, X2, [X2|L]) :-
H=X1,
rep(T,X1,X2,L),
!.
rep([H|T],X1,X2,[H|L]) :-
rep(T,X1,X2,L).
If you use SWI-Prolog, with module lambda.pl found there : http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl you can write :
:- use_module(library(lambda)).
rep(L, Rep, New_L) :-
maplist(\X^Y^(member(X=Z, Rep)
-> Y = Z
; Y = X), L, New_L).
You should attempt to keep the code simpler than possible:
rep([], _, []).
rep([X|Xs], Vs, [Y|Ys]) :-
( memberchk(X=V, Vs) -> Y = V ; Y = X ),
rep(Xs, Vs, Ys).
Of course, note the idiomatic way (thru memberchk/2) to check for a variable value.
Still yet a more idiomatic way to do: transforming lists it's a basic building block in several languages, and Prolog is no exception:
rep(Xs, Vs, Ys) :- maplist(repv(Vs), Xs, Ys).
repv(Vs, X, Y) :- memberchk(X=V, Vs) -> Y = V ; Y = X .
Here's how you could proceed using if_/3 and (=)/3.
First, we try to find a single Key in a list of pairs K-V.
An extra argument reifies search success.
pairs_key_firstvalue_t([] ,_ ,_ ,false).
pairs_key_firstvalue_t([K-V|KVs],Key,Value,Truth) :-
if_(K=Key,
(V=Value, Truth=true),
pairs_key_firstvalue_t(KVs,Key,Value,Truth)).
Next, we need to handle "not found" cases:
assoc_key_mapped(Assoc,Key,Value) :-
if_(pairs_key_firstvalue_t(Assoc,Key,Value),
true,
Key=Value).
Last, we put it all together using the meta-predicate maplist/3:
?- maplist(assoc_key_mapped([x-z,z-x,d-c]), [x,d,e,z,a,z,p], Rs).
Rs = [z,c,e,x,a,x,p]. % OK, succeeds deterministically
Let's improve this answer by moving the "recursive part" into meta-predicate find_first_in_t/4:
:- meta_predicate find_first_in_t(2,?,?,?).
find_first_in_t(P_2,X,Xs,Truth) :-
list_first_suchthat_t(Xs,X,P_2,Truth).
list_first_suchthat_t([] ,_, _ ,false).
list_first_suchthat_t([E|Es],X,P_2,Truth) :-
if_(call(P_2,E),
(E=X,Truth=true),
list_first_suchthat_t(Es,X,P_2,Truth)).
To fill in the "missing bits and pieces", we define key_pair_t/3:
key_pair_t(Key,K-_,Truth) :-
=(Key,K,Truth).
Based on find_first_in_t/4 and key_pair_t/3, we can write assoc_key_mapped/3 like this:
assoc_key_mapped(Assoc,Key,Value) :-
if_(find_first_in_t(key_pair_t(Key),_-Value,Assoc),
true,
Key=Value).
So, does the OP's use-case still work?
?- maplist(assoc_key_mapped([x-z,z-x,d-c]), [x,d,e,z,a,z,p], Rs).
Rs = [z,c,e,x,a,x,p]. % OK. same result as before
Building on find_first_in_t/4
memberd_t(X,Xs,Truth) :- % memberd_t/3
find_first_in_t(=(X),_,Xs,Truth).
:- meta_predicate exists_in_t(2,?,?). % exists_in_t/3
exists_in_t(P_2,Xs,Truth) :-
find_first_in_t(P_2,_,Xs,Truth).
I find your code rather confused. For one thing, you have rep/3 and rep/4, but none of them have a list in the second position where you're passing the list of variable bindings. H1=H2 cannot possibly match a list, and that's the only rep/3 clause that examines the second argument. If this is a class assignment, it looks like you're a little bit behind and I'd suggest you spend some time on the previous material.
The solution is simpler than you'd think:
rep([], _, []).
rep([X|Xs], Vars, [Y|Rest]) :- member(X=Y, Vars), rep(Xs, Vars, Rest).
rep([X|Xs], Vars, [X|Rest]) :- \+ member(X=_, Vars), rep(Xs, Vars, Rest).
We're using member/2 to find a "variable binding" in the list (in quotes because these are atoms and not true Prolog variables). If it's in the list, Y is the replacement, otherwise we keep using X. And you see this has the desired effect:
?- rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p] ;
false.
This could be made somewhat more efficient using "or" directly (and save us a choice point):
rep([], _, []).
rep([X|Xs], Vars, [Y|Ys]) :-
(member(X=Y, Vars), ! ; X=Y),
rep(Xs, Vars, Ys).
See:
?- rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p].