排除列表中所有出现的最小数量

时间:2015-07-29 02:47:25

标签: list prolog

作为一个Prolog新手,我尝试定义一个谓词filter_min/2,它使用两个列表来确定第二个列表是否与第一个列表相同,但是删除了所有出现的最小值。

带有预期结果的示例查询:

?- filter_min([3,2,7,8], N).
N = [3,7,8].

?- filter_min([3,2,7,8], [3,7,8]).
true.

我试过,但我总是得到相同的结果:false。我不知道问题是什么。我需要帮助!

这是我的代码:

filter_min(X,Y) :-
    X == [],
    write("ERROR: List parameter is empty!"),
    !;
    min_list(X,Z),
    filter(X,Y,Z).

filter([],[],0).
filter([H1|T1],[H2|T2],Z) :-
    \+ number(H1),
    write("ERROR: List parameter contains a non-number element"),
    !;
    H1 \= Z -> H2 is H1, filter(T1,T2,Z);
    filter(T1,T2,Z).

4 个答案:

答案 0 :(得分:4)

您的代码存在一些问题:

    使用任何没有0作为最小值的列表时,
  • filter([],[],0).将不会统一,这不是您想要的。无论结束递归的最小值,都希望它统一起来。
  • 您编写filter([H1|T1],[H2|T2],Z)及其正文的方式将使两个列表始终具有相同数量的元素,而实际上第二个列表应至少少一个。

filter/3的正确实施如下:

filter([],[],_).
filter([H1|T1],L2,Z):-
    \+ number(H1),
    write("ERROR: List parameter contains a non-number element"),
    !;
    H1 \= Z -> filter(T1,T2,Z), L2 = [H1|T2];
    filter(T1,L2,Z).

答案 1 :(得分:3)

提供赏金......

  

...对于一个纯粹的解决方案,它终止于(某些)第一个和第二个参数的长度都不知道的情况。

这是一个处理整数值的候选实现,构建于

:- use_module(library(clpfd)).

filter_min(Xs,Ys) :-
   filter_min_picked_gt(Xs,_,false,Ys).

filter_min_picked_gt([]    ,_,true  ,[]).
filter_min_picked_gt([Z|Xs],M,Picked,[Z|Zs]) :-
   Z #> M,
   filter_min_picked_gt(Xs,M,Picked,Zs).
filter_min_picked_gt([M|Xs],M,_,Zs) :-
   filter_min_picked_gt(Xs,M,true,Zs).

一些示例查询:

?- filter_min([3,2,7,8],[3,7,8]).
true ; false.                        % correct, but leaves choicepoint

?- filter_min([3,2,7,8],Zs).
Zs = [3,7,8] ; false.                % correct, but leaves choicepoint

现在,即使两个列表长度都未知,一些查询也会终止:

?- filter_min([2,1|_],[1|_]).
false.                               % terminates

?- filter_min([1,2|_],[3,2|_]).
false.                               % terminates

请注意,在逻辑错误的情况下,实现不会总是有限地失败(终止):

?- filter_min([1,2|_],[2,1|_]).      % does _not_ terminate

答案 2 :(得分:2)

首先,我们可以使用谓词list_minnum/2获取最小数字:

?- list_minnum([3,2,7,8],M).
M = 2.

我们可以像这样定义list_minnum/2

list_minnum([E|Es],M) :-
   V is E,
   list_minnum0_minnum(Es,V,M).

list_minnum0_minnum([],M,M).
list_minnum0_minnum([E|Es],M0,M) :-
   M1 is min(E,M0),
   list_minnum0_minnum(Es,M1,M).

为了完整起见,这里有超级相似的list_maxnum/2

list_maxnum([E|Es],M) :-
   V is E,
   list_maxnum0_maxnum(Es,V,M).

list_maxnum0_maxnum([],M,M).
list_maxnum0_maxnum([E|Es],M0,M) :-
   M1 is max(E,M0),
   list_maxnum0_maxnum(Es,M1,M).

接下来,我们使用 tfilter/3dif/3一起排除{strong>所有出现的M

?- M=2, tfilter(dif(M),[2,3,2,7,2,8,2],Xs).
Xs = [3,7,8].

将两个步骤放在一起并定义min_excluded/2

min_excluded(Xs,Ys) :-
   list_minnum(Xs,M),
   tfilter(dif(M),Xs,Ys).

让我们运行一些查询!

?- min_excluded([3,2,7,8],Xs).
Xs = [3,7,8].

?- min_excluded([3,2,7,8,2],Xs).
Xs = [3,7,8].

答案 3 :(得分:2)

对于Prolog新手,最好从基础开始。当第一个参数完全实例化时,以下工作正常,第二个参数是未实例化的变量,在输入列表的一次传递中计算结果。

% remmin( +From, -Result). 

% remmin([],[]).              % no min elem to remove from empty list
remmin([A|B], R):- 
  remmin(B, A, [A], [], R).   % remove A from B to get R, keeping [A]
                              % in case a smaller elem will be found

remmin([C|B], A, Rev, Rem, R):-  
  C > A -> remmin(B, A, [C|Rev], [C|Rem], R) ;
  C==A  -> remmin(B, A, [C|Rev],    Rem,  R) ;
  C < A -> remmin(B, C, [C|Rev],    Rev,  R).

remmin([], _, _, Rem, R) :- reverse(Rem, R).