测试列表是否表示没有重复项的集合的过程

时间:2012-01-25 17:20:54

标签: list prolog

在Prolog中,您如何编写一个可用于测试列表是否代表没有重复项的集合的过程?

6 个答案:

答案 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/2ground/1same_length/2iwhen/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_/3memberd_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/1http://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)).