我一直在尝试通过编写一个简单的程序来学习Prolog,该程序给定一个项目列表,并以相同的顺序返回/存储列表的副本,而不重复。例如:[1,1,2,3,3,5]返回[1,2,3,5]。我使用append将数字添加到一个空列表中,并使用成员检查是否已经添加了整数。
remove_duplicates([], R).
remove_duplicates([H|T], R) :-
member(H, R)
-> remove_duplicates(T, R)
; append(H, R),
remove_duplicates(T, R).
我已经让代码几乎可以工作了,但是当运行代码时,它会返回R=[1,2,3,6|_]。我尝试过跟踪和调试,但我不明白为什么最后会添加|_
。
我对代码的思考过程如下,如果我误解了什么,请指出。
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.
我对实现一个prolog谓词的问题的回答很接近,该谓词删除了@brebs所指出的所有重复元素,但它不会提供您想要的内容。这个
list_set( [] , [] ) .
list_set( [X|Xs] , Ys ) :- memberchk(X,Xs), !, list_set(Xs,Ys) .
list_set( [X|Xs] , [X|Ys] ) :- list_set(Xs,Ys) .
更喜欢重复项目的最后,因此
[1,2,3,3,2,1]
降低到
[3,2,1]
这违反了你的问题陈述中的约束,即你得到
列表的副本,没有相同顺序的重复项。
我们可以通过使用带有累加器的辅助谓词并引入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) .
这是迄今为止我发现的最快的方法(不使用append
或reverse
(:
https://stackoverflow.com/a/74024975/