Home > Software engineering >  Understanding print at the end of list when removing duplicates
Understanding print at the end of list when removing duplicates

Time:10-12

I've been trying to learn Prolog by writing a simple program that given a list of items, returns/stores a copy of the list without duplicates in the same order. Ex: [1,1,2,3,3,3,5] returns [1,2,3,5]. I'm using the append to add the numbers to an empty list and the member to check if the integer already has been added.

remove_duplicates([], R). 
remove_duplicates([H|T], R) :-
   member(H, R)
-> remove_duplicates(T, R)
;  append(H, R),
   remove_duplicates(T, R).

I've gotten the code to almost work, however when running the code it returns R = [1, 2, 3, 6|_]. I've tried tracing and debugging however I'm unable to understand why the |_ is added at the end.

My thought process for the code is as following, please point out if I'm misunderstanding something.

remove_duplicates([], R). % If first list is empty, return R. (Used to stop the recursion).
remove_duplicates([H|T], R) :-
   member(H, R)
-> remove_duplicates(T, R) % If head is member of R (=true), call remove:_duplicates again without the head. 
;  append(H, R),
   remove_duplicates(T, R). % else (if member(H, R) = false), add the head to list R and call remove_duplicates again with tail and R. 

CodePudding user response:

My answer to the question implement a prolog predicate that removes all duplicate elements as noted by @brebs is close, but it will not give you what you want. This

list_set( []     , []     ) .
list_set( [X|Xs] , Ys     ) :- memberchk(X,Xs), !, list_set(Xs,Ys) .
list_set( [X|Xs] , [X|Ys] ) :-                     list_set(Xs,Ys) .

prefers the last of duplicated items, so

[1,2,3,3,2,1]

reduces to

[3,2,1]

Which violates the constraint in your problem statement, that you get

a copy of the list without duplicates in the same order.

We can switch that up to prefer the first of any duplicate elements by using a helper predicate with an accumulator and introducing the use of append/3:

list_set( Xs , Ys ) :- list_set( Xs , [] , Ys ) .

list_set( []     , Ys , Ys ) .
list_set( [X|Xs] , Ts , Ys ) :- memberchk(X,Ts)   , ! , list_set(Xs,Ts,Ys) .
list_set( [X|Xs] , Ts , Ys ) :- append(Ts,[X],T1) ,     list_set(Xs,T1,Ys) .

CodePudding user response:

This is fastest method I've found so far (doesn't use append or reverse):

https://stackoverflow.com/a/74024975/

  • Related