在Prolog中,您如何编写一个可用于测试列表是否代表没有重复项的集合的过程?
答案 0 :(得分:3)
有几种方法可以做到这一点。 @thanosQR正确指向SWI-Prolog的is_set/1
,但是如果你想要一个可移植的解决方案,你可以用setof
来定义该谓词:
is_set(Lst) :-
setof(X, member(X, Lst), Set),
length(Lst, N),
length(Set, N).
如果列表的元素数等于setof
元素中的元素数,则列表不包含重复项。
你也可以使用(我相信非标准,但通常可用)sort/2
,这可以消除重复:
is_set(Lst) :-
sort(Lst, Set),
length(Lst, N),
length(Set, N).
这需要运行O( n lg n )时间。
答案 1 :(得分:2)
首先,定义谓词以确保值不在列表中:
notin(A,[]).
notin(A,[B|C]) :- A\=B, notin(A,C).
然后,我们的nodups谓词确保每个元素不会出现在它之后的列表部分中:
nodups([]).
nodups([_]).
nodups([A|B]) :- notin(A,B), nodups(B).
答案 2 :(得分:2)
使用sort/2
,ground/1
,same_length/2
和iwhen/2
:
:- use_module(library(lists)).
is_set(S) :-
iwhen(ground(S), (same_length(S,T), sort(S,T))).
样本使用:
?- is_set([4,1,3,2]). % not in standard order true. % OK: no duplicates ?- is_set([1,2,3,1,2]). false. ?- is_set([1,2,3,1,X]). ERROR: Arguments are not sufficiently instantiated
答案 3 :(得分:2)
我们根据if_/3
和memberd_t/3
定义distinct_t/2
:
distinct_t([], true).
distinct_t([X|Xs], T) :-
if_(memberd_t(X,Xs), T=false, distinct_t(Xs,T)).
让我们从distinct_t/2
的最常见用法开始:
?- distinct_t(Xs,T).
T = true , Xs = []
; T = true , Xs = [_A]
; T = false, Xs = [_A,_A|_B]
; T = true , Xs = [_A,_B], dif(_B,_A)
; T = false, Xs = [_A,_B,_A|_C], dif(_B,_A)
; T = false, Xs = [_A,_B,_B], dif(_B,_A), dif(_B,_A)
; T = true , Xs = [_A,_B,_C], dif(_B,_A), dif(_C,_A), dif(_C,_B)
...
好的!这个相当普遍的查询怎么样?
?- distinct_t([1,2,X,3],T).
T = false, X = 1
; T = false, X = 2
; T = false, X = 3
; T = true , dif(X,1), dif(X,2), dif(X,3).
如果我们只对T = true
的案例感兴趣,我们会使用dictinct/1
- 定义如下:
distinct(Xs) :-
distinct_t(Xs, true).
示例查询:
?- distinct([1,2,3,1]). false. ?- distinct([1,2,3,2]). false. ?- distinct([1,2,3,3]). false. ?- distinct([1,2,3,4]). true. % succeeds deterministically
答案 4 :(得分:1)
is_set/1
:http://www.swi-prolog.org/pldoc/doc_for?object=is_set/1
(假设你仍然想要它用于swi-prolog)
答案 5 :(得分:0)
is_set/1
更糟,但是没有):
duplicates(List) :-
forall(select(Item, List, Rest),
forall(member(Item2, Rest),
Item \== Item2)).