2013-11-28 26 views
5

Sto cercando di rimuovere le voci duplicate da un elenco in prolog. Quindi una lista [a, b, a, c, b, a] restituirebbe [a, b, c]. Non posso usare nessuna funzione incorporata. Ho cercato qui e ho trovato questo codice.Prolog: rimozione dei duplicati

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). 

ma che avrebbe preso la mia lista e ritornare [c, b, a] non [a, b, c]

devo rimuovere il codice che avrà un elemento e una lista e restituire un elenco con occorrenze di quell'elemento nell'elenco rimosso. Così ho cercato di incorporarlo nel mio metodo di rimozione dei duplicati, ma non capisco molto bene il prolog, quindi non funziona. Logicamente voglio prendere una lista contro la testa con la chiamata ricorsiva sulla nuova lista meno tutte le occorrenze della testa. Questo è come apparirebbe il codice 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)); 

Quindi questo è quello che ho provato nel prologo

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). 

Che cosa mi manca?

risposta

7
% 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). 
+0

Grazie a SQB è esattamente la logica di ciò che stavo cercando di fare. Anche guardando il tuo codice non riesco a trovare dove ho fatto il mio errore, loro hanno letto lo stesso per me. Eppure il tuo funziona e il mio rimane bloccato in un loop infinito. – user3043403

+0

hmm penso di aver capito, ordine entro: - è importante quindi la mia linea. remvdub ([H | T], [H | Ans]): - remvdub (Ans1, Ans), remv (H, T, Ans1). Dovrebbe essere remvdub ([H | T], [H | Ans]): - remv (H, T, Ans1), remvdub (Ans1, Ans). – user3043403

2

Lo snippet di codice Prolog che hai postato è logicamente corretto. Se si desidera mantenere la prima, in contrasto con l'ultimo, copia di ogni elemento duplicato, è possibile modificare il codice come segue:

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). 

L'idea è quella di aggiungere un terzo parametro, che rappresenta l'elenco delle elementi che hai visto fino ad ora, e controlla l'appartenenza contro di essa, piuttosto che controllare l'appartenenza alla lista rimanente. Si noti che set/2 viene aggiunto per nascondere questo terzo argomento agli utenti del predicato.

Demo on ideone.

+0

Grazie dasblinkenlight, che ha funzionato! Per curiosità c'è un modo per fare ciò che stavo cercando nel blocco inferiore del codice? Dove uso il codice di rimozione per inserire elenchi progressivi più piccoli con la testa e i duplicati della testa rimossi? – user3043403

+0

@ user3043403 Non capisco sml, quindi non riesco a dare un senso al codice prototipo funzionante. La seconda clausola del predicato 'remvdub/2' sembra tuttavia molto sospettosa, perché sembra che stia procedendo verso una ricorsione infinita. – dasblinkenlight

Problemi correlati