2

I'm attempting to find the complement of a list, given a list L1, and a universal list L2 with the following code:

complement(L1, L2, Res):-
    setof(X, (nth0(N, L2, X), not(member(X,L1))),Res).

However, my results include duplicates and are not given in list form as I'd prefer:

23 ?- complement([1,3], [-1,1,3,5,2,4,2,55,1,0], Res).
Res = [-1] ;
Res = [5] ;
Res = [2] ;
Res = [4] ;
Res = [2] ;
Res = [55] ;
Res = [0].

I figured it's probably due to Prolog's built-in backtracking but I'm not sure how to work around this to go about formatting the result correctly and getting it to remove any duplicate items in the result.

false
  • 10,264
  • 13
  • 101
  • 209
Zenadia Groenewald
  • 107
  • 1
  • 3
  • 12

1 Answers1

3

You get a warning from your code, about N being a singleton, and setof/3 requires that each variable 'universally quantified' get declared. So, you have two problems that go away together: replace nth0/3 by member/2:

complement(L1, L2, Res):-
    setof(X, (member(X, L2), not(member(X, L1))), Res).

edit

symmetric difference could be

symdiff(L1,L2,Diff) :-
    setof(X,(eldiff(L1,L2,X);eldiff(L2,L1,X)),Diff).
eldiff(L1,L2,X) :-
    member(X,L1), \+member(X,L2).

if L1 and L2 are ordered sets, much better to use ord_symdiff

CapelliC
  • 59,646
  • 5
  • 47
  • 90
  • That fixed it. Thank you :) – Zenadia Groenewald Jul 27 '16 at 12:28
  • Is there a way to do this both ways, i.e. not the complement but elements from both that are not in the other, i.e. symmetric difference, also using setof/findall/bagof? I have done it the long way but the above solution could it be used to achieve this ? – ildsarria Jul 11 '17 at 15:08
  • @ildsarria: sorry, I'm not sure. Symmetric difference can be computed - IIRC - from library(ordsets) – CapelliC Jul 11 '17 at 17:37