Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prolog: Removing Duplicates

Tags:

prolog

I am trying to remove duplicate entries from a list in prolog. So a list [a,b,a,c,b,a] would return [a,b,c]. I can not use any built in functions. I searched here and found this code.

member(X,[X|_]) :- !.
member(X,[_|T]) :- member(X,T).
set([],[]).
set([H|T],[H|Out]) :- not(member(H,T)), set(T,Out).
set([H|T],Out) :- member(H,T), set(T,Out).

But that would take my list and return [c,b,a] not [a,b,c]

I have remove code that will take an element and a list and return a list with occurrences of that element in the list removed. So I tried to incorporate that into my remove duplicate method but I don't really understand prolog very well so it is not working. Logically I want to take a list cons the head with the recursive call on the new list minus all occurrences of the head. This is what the code would look like in sml.

fun remv(_,nil) = nil
|   remv(a,x::xs) = if x=a then remv(a,xs) else x::remv(a,xs);
fun remvdub (nil) = nil
|   remvdub(x::xs) = x::remvdub(remv(x,xs)); 

So this is what I tried in prolog

remv(_,[],[]).
remv(X,[X|T],Ans) :- remv(X,T,Ans).
remv(X,[H|T],[H|K]) :- remv(X,T,K). 

remvdub([],[]).
remvdub([H|T],[H|Ans]) :- remvdub(Ans1,Ans), remv(H,T,Ans1).

What am I missing?

like image 234
user3043403 Avatar asked Nov 28 '13 02:11

user3043403


People also ask

How do I remove an item from a list in Prolog?

This predicate can be used to select an element from a list, delete an element or insert it. The definition of this Prolog library predicate is: delete(A, [A|B], B). delete(A, [B, C|D], [B|E]) :- delete(A, [C|D], E).

How do you use not in Prolog?

Because of the problems of negation-as-failure, negation in Prolog is represented in modern Prolog interpreters using the symbol \+ , which is supposed to be a mnemonic for not provable with the \ standing for not and the + for provable.

What is member in Prolog?

If Term is a variable and List is a list, all the members of the list List are found on backtracking. If List is not instantiated, member/2 binds List to a new partial list containing the element Term. The definition of this Prolog library predicate is: member(X,[X|_]). member(X,[Y|T]) :- member(X,T).


2 Answers

% An empty list is a set.
set([], []).

% Put the head in the result,
% remove all occurrences of the head from the tail,
% make a set out of that.
set([H|T], [H|T1]) :- 
    remv(H, T, T2),
    set(T2, T1).

% Removing anything from an empty list yields an empty list.
remv(_, [], []).

% If the head is the element we want to remove,
% do not keep the head and
% remove the element from the tail to get the new list.
remv(X, [X|T], T1) :- remv(X, T, T1).

% If the head is NOT the element we want to remove,
% keep the head and
% remove the element from the tail to get the new tail.
remv(X, [H|T], [H|T1]) :-
    X \= H,
    remv(X, T, T1).
like image 70
SQB Avatar answered Sep 25 '22 02:09

SQB


The snippet of Prolog code that you posted is logically correct. If you would like to keep the first, as opposed to the last, copy of each duplicated item, you can change your code as follows:

member(X,[X|_]) :- !.
member(X,[_|T]) :- member(X,T).
set(A,B) :- set(A, B, []).
set([],[],_).
set([H|T],[H|Out],Seen) :- not(member(H,Seen)), set(T,Out, [H|Seen]).
set([H|T],Out, Seen) :- member(H,Seen), set(T,Out,Seen).

The idea is to add a third parameter, which represents the list of items that you have seen so far, and check the membership against it, rather than checking the membership against the remaining list. Note that set/2 is added to hide this third argument from the users of your predicate.

Demo on ideone.

like image 25
Sergey Kalinichenko Avatar answered Sep 27 '22 02:09

Sergey Kalinichenko