Prolog删除所有变量和重复项

时间:2013-05-02 17:59:48

标签: list prolog

我需要一个查询,它会从列表中删除所有变量重复项

示例:

?- L = [1,2,3,X,Y,3,2], my_awesome_predicate(L, Res).

然后,Res应该是:[1,2,3]。

我不关心秩序(可能是[2,3,1],[3,2,1]或其他)。

不幸的是,我有一个任务,我必须关心效率,所以我的主要问题是 - 它可以更快地完成吗?目前,我有以下代码:

remove_variables([], []).
remove_variables([H|List], Res):- var(H), !, remove_variables(List, Res).
remove_variables([H|List], [H|Res]):- remove_variables(List, Res).

my_awesome_predicate([], []).
my_awesome_predicate(List, Res):-
  sort(List, Sorted),
  remove_variables(Sorted, Res).

3 个答案:

答案 0 :(得分:2)

如果您正在使用 SWI ,那么您可以使用此代码进一步改进:

my_awesome_predicate(List, Res):-
  sort(List, MRes),
  remove_variables(MRes, Res).

remove_variables([Var|Tail], NTail):-
  var(Var),
  !,
  remove_variables(Tail, NTail).
remove_variables(Res, Res).

因为似乎SWI的排序将首先留下无界变量(不知道这种行为是否是其他prolog的标准),所以你可以在找到第一个非变量后停止删除变量。

读一点SWI's documentation,声明:

4.7.1 Standard Order of Terms

Comparison and  unification of arbitrary  terms.   Terms are ordered  in
the so called ``standard order''.  This order is defined as follows:

 1. Variables < Numbers < Atoms < Strings < Compound Terms

因此,当您找到第一个非变量...

时,停止删除元素似乎是安全的

答案 1 :(得分:1)

awesome([],[]).
awesome([H|T],R):- var(H), !, awesome(T,R).
awesome([H|T],R):- awesome(T,[H],R).

awesome([],R,R).
awesome([H|T],A,R):- memberchk(H,A) -> awesome(T,A,R) ; awesome(T,[H|A],R).

这样的东西?从理论上讲它是二次的,但是你的列表很短,而且这段代码非常简单,所以编译器可能会更好地优化它们。

如果附加结果列表,最好更改它以使用差异列表,将输出直接放入正在构建的结果列表中:

awesome([],Z,Z).
awesome([H|T],R,Z):- var(H), !, awesome(T,R,Z).
awesome([H|T],R,Z):- R=[H|Y], awesome(T,[H],Y,Z).

awesome([],_,Z,Z).
awesome([H|T],A,R,Z):- memberchk(H,A) -> awesome(T,A,R,Z) 
                                      ;  R=[H|Y], awesome(T,[H|A],Y,Z).

memberchk/2当然会清除变量和重复项。

答案 2 :(得分:0)

这是一个古老的问题,但是作为参考,还有一个使用setof的不错的简短解决方案。

my_awesome_predicate(L, Res) :-
    setof(X, (member(X, L), ground(X)), Res).

Res包含不带变量的解决方案,其变量按其首次出现的顺序排列。

?- my_awesome_predicate([1,2,3,X,Y,3,2], Res).
Res = [1, 2, 3].