I am trying to write a program which takes a list containing lists, and then compares the lists inside. If any two lists contain the same information, such as them both containing X, then I want to remove X from both lists. How could I go about this?
This seems to do it:
dedupe(Lists, Result) :-
append(Lists, Flat),
findall(E, (select(E, Flat, FlatNoE), \+ memberchk(E, FlatNoE)), Uniques),
subtract(Flat, Uniques, Unwanted),
findall(Rs, (member(Ls, Lists), subtract(Ls, Unwanted, Rs)), Result).
e.g.
?- dedupe([[1,2,3], [1,2,5,6,1], [4,1,2,1]], R).
R = [[3], [5, 6], [4]]
The design is:
append/2
.select
and seeing if that element still exists in the rest of the values with memeberchk
.subtract
does a list-from-list subtraction to remove the unique elements from all the elements, leaving the Unwanted
duplicate elements.findall
then runs subtract over the sublists, removing the duplicaates from each one.It's possible in SWI Prolog to rewrite the last line as:
maplist({Unwanted}/[Ls, Ls_]>>subtract(Ls, Unwanted, Ls_), Lists, Result).
fwiw. In small testing they have almost identical timing/inferences to solve.