如何在SWI Prolog中从列表中删除重复项?
我需要编写一个谓词如何在SWI Prolog中从列表中删除重复项?,prolog,Prolog,我需要编写一个谓词remove_duplicates/2,从给定列表中删除重复元素。例如: remove_duplicates([a,a,b,c],L). L = [a, b, c] ; false. ?-删除重复项([a,a,b,c,c],列表)。列表=[a、b、c]是 请记住,我只学习了两天的SWI Prolog,并且只了解Prolog的基础知识。这就是我目前的情况: remove_duplicates([H | T],List):-member(H,T),append(T,[],List
remove_duplicates/2
,从给定列表中删除重复元素。例如:
remove_duplicates([a,a,b,c],L).
L = [a, b, c] ;
false.
?-删除重复项([a,a,b,c,c],列表)。列表=[a、b、c]是
请记住,我只学习了两天的SWI Prolog,并且只了解Prolog的基础知识。这就是我目前的情况:
remove_duplicates([H | T],List):-member(H,T),append(T,[],List1)代码>
这适用于列表[a,a,b,c]
,但不适用于尾部两个元素相同的列表。我想我必须以某种方式将Head移到一个临时列表中,创建一个新的Head,然后重复谓词。我不知道怎么做。此外,当头部不在尾部时,例如使用类似于[a,b,b,c]
的列表时,终端只会说False
,因为成员(H,T)
不是真的
有什么想法吗?谓词有一些问题:
remove_duplicates([H | T], List) :-
member(H, T),
append(T, [], List1).
首先,应该有一个递归谓词,检查列表的开头,但不递归检查列表的结尾:
因此,您可以将其更改为:
remove_duplicates([H | T], List) :-
member(H, T),
remove_duplicates( T, List).
上面递归地调用尾部
其次,您必须决定如果h不是列表中的成员会发生什么,因此您需要添加另一个子句:
remove_duplicates([H | T], [H|T1]) :-
\+member(H, T),
remove_duplicates( T, T1).
上面检查T中是否存在H,如果不存在,则强制列表中要返回的第一个元素为元素H:
如果这一点不清楚,则上述内容等于:
remove_duplicates([H | T], List) :-
\+member(H, T),
List=[Head|Tail],
Head=H,
remove_duplicates( T, Tail).
这不是很优雅,只是为了了解以前的作品
最后,您需要一个空列表递归的基:
remove_duplicates([],[]).
因此,根据上述条款,谓词remove_duplicates应为:
remove_duplicates([],[]).
remove_duplicates([H | T], List) :-
member(H, T),
remove_duplicates( T, List).
remove_duplicates([H | T], [H|T1]) :-
\+member(H, T),
remove_duplicates( T, T1).
尽管您必须注意,上面的每个元素只保留一次,例如:
remove_duplicates([a,a,b,c],L).
L = [a, b, c] ;
false.
这是可以的,但请检查以下示例:
remove_duplicates([a,a,b,a,c],L).
L = [b, a, c] ;
L = [b, a, c] ;
false.
这将返回L=[b,a,c],因为它删除了列表的前两个“a”,只保留了第三个
如果只希望删除重复项,由于成员谓词的原因,上述操作将不起作用。
你可以写:
remove_duplicates2([],[]).
remove_duplicates2([H],[H]).
remove_duplicates2([H ,H| T], List) :-remove_duplicates( [H|T], List).
remove_duplicates2([H,Y | T], [H|T1]):- Y \= H,remove_duplicates( [Y|T], T1).
谓词remove_duplicates 2与remove_duplicates类似,但有一些重要区别:
1) 您不使用member,但可以检查当列表[H,H | t]包含两个相同的元素且只保留一个元素时会发生什么,因此忽略第一个H并递归调用remove|u duplicates2([H | t],L)
2) 如果输入了[H,Y | T](至少包含两个元素H,Y和列表尾部的列表)和H\=Y,则调用remove_duplicates2([Y | T],T1),并将H存储到要返回的列表中
3) 最后,因为all子句至少需要两个元素,所以递归的基础是包含一个元素的列表:remove_duplicates2([H],[H])
4) 该子句删除重复项2([],[])。仅当输入为空列表时使用,因此需要覆盖此输入
remove_duplicates2谓词将为您提供:
remove_duplicates2([a,a,b,a,c],L).
L = [a, b, a, c] ;
false.
remove_duplicates2([a,a,b,c],L).
L = [a, b, c] ;
false.
要删除重复项,如果顺序无关紧要,最简单的方法是使用sort/2
:
?- sort([a,a,b,b,c], X).
X = [a, b, c].
?- sort([c,c,a,a,b], X).
X = [a, b, c].
当然,您会看到元素的原始顺序丢失了。更重要的是,只有在您正在排序的列表已经被归零(其中没有自由变量)的情况下,这才保证是正确的。考虑这个小例子:
?- sort([X,Y], [a,a]).
X = Y, Y = a.
如果您的目标是删除重复项,则感觉不完全正确
所以你不妨写下:
must_be(ground, List), sort(List, Unique).
你也可以自己做,并保持原来的秩序。但是,您需要记录到目前为止看到的元素。例如,您可以将它们保留在额外列表中:
到目前为止看到的元素列表在开头是空的
如果到目前为止看到的所有元素都与X不同,
将其放在唯一元素列表中,并将其添加到
到目前为止看到的元素列表
如果到目前为止已看到该元素,请跳过它
这是最直接的方法。还有其他更聪明的方法可能会更复杂,但这是最容易编写的方法。您可以使用或,如这里的答案所述
% remdup(List, List_No_duplicates).
remdup([],[]).
remdup([H|T],Lnd):- rd1(H,T,T1), remdup(T1,Tnd),Lnd=[H|Tnd].
% rd1(X,L,Lr) removes all occurance of X in List L and store result in List Lr
rd1(_,[],[]).
rd1(X,[X|T],Lx):- rd1(X,T,Lx).
rd1(X,[Y|T],Lx):- rd1(X,T,Lx1),Lx=[Y|Lx1].
如何工作-谓词remdup
取给定列表中的第一个元素H,并删除其在尾部T中的所有引用-将该结果存储在列表T1中;及
在Tnd中的T1存储结果上递归调用remdup;及
将元素H添加回Tnd,它实际上是尾部T,由remdup的递归调用修改,因此已经没有所有重复项,并且不包含任何H的出现
谓词-rd1
从空白列表中删除所有事件和任何内容都是空白列表
如果头部匹配X-则继续在尾部再次调用
如果头部与X不匹配,则继续到尾部;并将不匹配的头部Y添加到修改后的尾部,该尾部现在不再出现X
试试这个,我希望它能帮助你:
delete3(_,[],[]).
delete3(X,[X|T],R):- delete3(X,T,R).
delete3(X,[H|T],[H|R]) :- delete3(X,T,R).
remove_duplicates([],[]).
remove_duplicates([H|T], [H|R]) :-
member(H,T),!,
delete3(H,T,R1),
remove_duplicates(R1,R).
remove_duplicates([H|T],[H|R]):-
remove_duplicates(T,R).
在第二个谓词中,我们验证head变量*(H)*是否是列表*(T)*尾部的成员。如果是,那么我们调用第一个谓词,该谓词删除所有与尾部的head变量相等的变量,依此类推。查询排序([a,X,b,X],L),X=b如何。
?它会导致L=[b,a,b]
,我认为这是不需要的。@lambda.xy.x是的,即使这样:排序([x,Y],[a,a])
也证明了同样的问题。排序不是逻辑操作,其语义是:“根据术语的标准顺序对第一个参数中的列表进行排序,并将结果与第二个参数统一起来”。您可以查看更多示例。更正了我的答案。@lambda.xy.x的可能副本在[prolog]标签上有许多类似的问题和答案,但是,我不确定提议的(和接受的)解决方案是否一定那么好。我不认为我下面的答案更好,但至少它显示了一种不同的方法。你是对的,有很多不纯的解决方案
% remdup(List, List_No_duplicates).
remdup([],[]).
remdup([H|T],Lnd):- rd1(H,T,T1), remdup(T1,Tnd),Lnd=[H|Tnd].
% rd1(X,L,Lr) removes all occurance of X in List L and store result in List Lr
rd1(_,[],[]).
rd1(X,[X|T],Lx):- rd1(X,T,Lx).
rd1(X,[Y|T],Lx):- rd1(X,T,Lx1),Lx=[Y|Lx1].
delete3(_,[],[]).
delete3(X,[X|T],R):- delete3(X,T,R).
delete3(X,[H|T],[H|R]) :- delete3(X,T,R).
remove_duplicates([],[]).
remove_duplicates([H|T], [H|R]) :-
member(H,T),!,
delete3(H,T,R1),
remove_duplicates(R1,R).
remove_duplicates([H|T],[H|R]):-
remove_duplicates(T,R).