我试图编写一个简单的程序来检查列表是否有重复项。这是我到目前为止所尝试的:
% returns true if the list has no duplicate items.
no_duplicates([X|XS]) :- member(X,XS) -> false ; no_duplicates(XS).
no_duplicates([]) :- true.
如果我尝试no_duplicates([1,2,3,3])
。它说的是真的。为什么是这样?我可能在这里误解了Prolog,但感谢任何帮助。
答案 0 :(得分:7)
回答您的问题:您的解决方案实际上无法按预期no_duplicates([1,2,3,3])
失败。所以没有问题。
现在进行查询:
?- A = 1, no_duplicates([A, 2]).
A = 1.
?- no_duplicates([A, 2]), A = 1.
它们都意味着相同,所以我们应该期待Prolog会产生相同的答案。 (更确切地说,我们期望相同的忽略错误和非终止)。
然而,四个提议的解决方案不同!而那个没有的,不同的是:
?- A = 2, no_duplicates([A, 2]).
false.
?- no_duplicates([A, 2]), A = 2.
请注意,它始终是第二个产生麻烦的查询。要解决这个问题,我们需要no_duplicates([A, 2])
的答案。它不能是false
,因为A
有一些值可以使其成立。像A = 1
一样。它也不是真的,因为有些值不适合,例如A = 2
。
另一种可能性是在这种情况下发出instantiation_error
。含义:我没有足够的信息,所以我最好停下来,而不是弄乱可能不正确的信息。
理想情况下,我们会得到一个涵盖所有可能解决方案的答案。这个答案是dif(A, 2)
,这意味着与2不同的所有A
都是解决方案。
dif/2
是最古老的内置谓词之一,Prolog 0确实拥有它。不幸的是,后来的发展在Prolog I和Edinburgh Prolog以及ISO Prolog中丢弃了它。
然而,包括SICStus,YAP,SWI在内的现有系统都提供它。在ISO-Prolog
中有一种安全的approximatedif/2
safely方式
no_duplicates(Xs) :-
all_different(Xs). % the common name
all_different([]).
all_different([X|Xs]) :-
maplist(dif(X),Xs).
all_different(Xs).
请参阅:prolog-dif
答案 1 :(得分:2)
列表中的重复项是列表中不在同一位置的相同元素,因此可以写入no_duplicates:
no_duplicates(L) :-
\+((nth0(Id1, L, V), nth0(Id2, L, V), Id1 \= Id2)).
答案 2 :(得分:2)
我会更具描述性地解决问题:
no_duplicates( [] ) . % the empty list is unique
no_duplicates( [X|Xs] ) :- % a list of length 1+ is unique
\+ member(X,Xs) , % - if its head is not found in the tail,
no_duplicates(Xs) % - and its tail is itself unique.
. %
考虑到这一点,因为这是一个有点昂贵的操作 - O(n 2 )? - 使用sort/2
可能更有效,并利用它生成有序集,删除重复的事实。你可以说像
no_duplicates( L ) :-
sort(L,R) % sort the source list, removing duplicates
length(L,N) , % determine the length of the source list
Length(R,N) , % check that against the result list
.
或者您可以使用msort/3
(不会删除重复项),也可能会更快一点:
no_duplicates( L ) :-
msort(L,R), % order the list
\+ append(_,[X,X|_],R) % see if we can find two consecutive identical members
.
答案 3 :(得分:2)
这是另一种方法,可行,因为sort/2
删除了重复项:
no_duplicates(L) :-
length(L, N),
sort(L, LS),
length(LS, N).
答案 4 :(得分:1)
no_duplicates(L) :- \+ (append(_, [X|XS], L), memberchk(X, XS)).