Using reif library, to be both pure and reasonably deterministic (similar answer):
:- use_module(library(reif)).
duplicate_elements(LstFull, LstDuplicates) :-
duplicate_elements_(LstFull, [], LstDuplicatesRev),
reverse(LstDuplicatesRev, LstDuplicates).
duplicate_elements_([], L, L).
% U means LstUpto
duplicate_elements_([H|T], U, LstD) :-
memberd_t(H, T, Bool),
(Bool == true -> duplicate_elements_add_(U, H, U1) ; U1 = U),
duplicate_elements_(T, U1, LstD).
duplicate_elements_add_(U, E, U1) :-
% Prevent adding a duplicate to U1 more than once
(memberchk(E, U) -> U1 = U ; U1 = [E|U]).
Result in swi-prolog:
?- time(duplicate_elements([a,b,1,2,c,A,2,1,4], D)).
% 105 inferences, 0.000 CPU in 0.000 seconds (92% CPU, 1494726 Lips)
A = a,
D = [a,1,2] ;
% 177 inferences, 0.000 CPU in 0.000 seconds (94% CPU, 1261726 Lips)
A = b,
D = [b,1,2] ;
% 193 inferences, 0.000 CPU in 0.000 seconds (98% CPU, 1288643 Lips)
A = 1,
D = [1,2] ;
% 214 inferences, 0.000 CPU in 0.000 seconds (96% CPU, 1349996 Lips)
A = 2,
D = [1,2] ;
% 237 inferences, 0.000 CPU in 0.000 seconds (98% CPU, 1515152 Lips)
A = c,
D = [1,2,c] ;
% 360 inferences, 0.000 CPU in 0.000 seconds (99% CPU, 1892217 Lips)
A = 4,
D = [1,2,4] ;
% 49 inferences, 0.000 CPU in 0.000 seconds (95% CPU, 575563 Lips)
D = [1,2],
dif(A,a),
dif(A,4),
dif(A,c),
dif(A,2),
dif(A,1),
dif(A,b).