Reputation: 67
Good day, guys. Can't figure out, why prolog predicate is putting all duplicates into my new list. F.e. I have to pick all duplicates:
?- duplicates([a, b, a, a, d, d], R).
R = [a, d]
I have wrote this prolog program:
duplicates([], []).
duplicates([First|Rest], NewRest) :-
not(member(First, Rest)),
duplicates(Rest, NewRest).
duplicates([First|Rest], [First|NewRest]) :-
member(First, Rest),
duplicates(Rest, NewRest).
But it returns:
R = [a, a] .
I think I need to put a (!) sign somewhere, but cannot understand, where. Any suggestions?
Upvotes: 2
Views: 87
Reputation: 3736
Try this:
duplicates([], []).
duplicates([First|Rest], NewRest) :-
\+ member(First, Rest),
duplicates(Rest, NewRest).
duplicates([First|Rest], NewRest) :-
duplicates(Rest, NewRest),
member(First, NewRest).
duplicates([First|Rest], [First|NewRest]) :-
member(First, Rest),
duplicates(Rest, NewRest),
\+ member(First, NewRest).
?- duplicates([a, b, a, a, d, d], R).
R = [a, d] ;
false.
I have choosen a version where you don't need cuts (the !
). Also I added another rule: elements in NewRest
can appear only once. Note: membership in NewRest
can be testet only after unification of all of its entries.
Upvotes: 1
Reputation: 60004
library(aggregate) allows a compact solution for your problem.
duplicates(L,D) :- findall(K,(aggregate(count,member(K,L),C),C>1),D).
?- duplicates([a, b, a, a, d, d], R).
R = [a, d].
Clearly, it's less immediate to grasp than @Raubsauger' good answer, and not available in every Prolog out there.
Upvotes: 2