2

Compute the symmetric difference of two lists and return a third list containing no duplicates.

Sample query showing expected results:

?- join([a,b,p,l,a,f],[q,a,z,x,l],Rs).
Rs = [b,p,f,q,z,x].

I currently have this code:

join([],List,List).
join([H|T],List,[H|Result]) :-
    not(member(H,List)),
    join(T,List,Result).
join([H|T],Y,Z) :-
    join(T,Y,Z).

It can find all the elements that do not repeat, but it places them all as the head on the second list.

How can I make it so the second list is also checked for elements that are repeated and only output those which are not?

false
  • 10,264
  • 13
  • 101
  • 209

3 Answers3

2

The "non-intersection" you describe seems to be the symmetric difference of two sets, which is the union of both their (asymmetric) set differences. Set difference can be computed with the SWI-Prolog subtract/3 predicate or the solution to this problem.

Getting the union can be done with append/3 followed by sort/2, which takes care of the duplicates.

Community
  • 1
  • 1
Fred Foo
  • 355,277
  • 75
  • 744
  • 836
1

The following implementation preserves . It is based on:

Let's get straight to the code!

list_list_symdiffset([],Ys,Zs) :-
   list_setB(Ys,Zs).
list_list_symdiffset([X|Xs0],Ys0,Zs0) :-
   tpartition(=(X),Ys0,Es,Ys1),
   if_(Es=[], Zs0=[X|Zs1], Zs0=Zs1),
   tfilter(not_t(=(X)),Xs0,Xs1),
   list_list_symdiffset(Xs1,Ys1,Zs1).

Let's run the sample query given by the OP:

?- list_list_symdiffset([a,b,p,l,a,f],[q,a,z,x,l],Rs).
Rs = [b,p,f,q,z,x].                   % succeeds deterministically

At last, let's try something more general!

?- list_list_symdiffset([A,B],[X,Y],Ys).
Ys = [],        A=B, B=X, X=Y ;
Ys = [B],       A=X, X=Y, dif(Y,B) ;
Ys = [Y],       A=B, B=X, dif(X,Y) ;
Ys = [],        A=X, B=Y, dif(X,Y), dif(X,Y) ;
Ys = [B,Y],     A=X, dif(X,B), dif(X,Y), dif(B,Y) ;
Ys = [X],       A=B, B=Y, dif(Y,X) ;
Ys = [],        A=Y, B=X, dif(Y,X), dif(Y,X) ;
Ys = [B,X],     A=Y, dif(Y,B), dif(Y,X), dif(B,X) ;
Ys = [B,Y],     A=B, X = Y, dif(B,Y), dif(B,Y) ;
Ys = [B,X,Y],   A=B, dif(B,Y), dif(B,X), dif(X,Y) ;
Ys = [A],       B=X, X=Y, dif(A,Y), dif(A,Y),dif(A,Y) ;
Ys = [A,Y],     B=X, dif(A,X), dif(A,Y), dif(A,X), dif(X,Y) ;
Ys = [A,X],     B=Y, dif(A,Y), dif(A,Y), dif(A,X), dif(Y,X) ;
Ys = [A,B,Y],   X=Y, dif(A,B), dif(A,Y), dif(A,Y), dif(B,Y), dif(B,Y) ;
Ys = [A,B,X,Y], dif(A,B), dif(A,Y), dif(A,X), dif(B,Y), dif(B,X), dif(X,Y).
Community
  • 1
  • 1
repeat
  • 18,496
  • 4
  • 54
  • 166
0

join(L1,L2,L) :-
        append(L1,L2,L3),
        findall(A,unique(L3,A),L).

unique(L3,A) :-
        append(L0,[A|R],L3),
        \+(append(_,[A|_],L0)).
尾崎隆大
  • 148
  • 1
  • 1
  • 1
    This definition of `join/3` returns the set of unique elements of a concatenation of two lists, which is not what the OP asked for. –  May 19 '11 at 02:07