Prolog - 如何计算列表中满足特定条件的元素数量?

时间:2017-10-24 05:10:57

标签: list prolog

例如,如果我有一个列表[1,1,2,3,5,1],我想计算此列表中1的数量,我该怎么做?

我写了类似的东西:

count([], 0).
count([H|T], N) :-
   count(T, X),
   (  H =:= 1
   -> N is X+1
   ;  N is X
   ),
   N > 0.

在这个递归中,如果Head等于1,我想做,然后计数+ 1,如果Head不是1,那么计数保持不变。但是,如果列表中的值不是1,则返回false。我知道问题是,一旦元素不满足if语句,它就会失败;它永远无法达到else语句。我该如何解决?请帮忙!!!!

4 个答案:

答案 0 :(得分:3)

替代解决方案,它使用foldl / 4并定义更高阶谓词(将另一个谓词作为参数的谓词):

count_step(Condition, Item, CurrentCount, NewCount) :-
    call(Condition, Item) ->
        NewCount is CurrentCount + 1 ;
        NewCount = CurrentCount.

count(List, Condition, Count) :-
    foldl(count_step(Condition), List, 0, Count).

is_one(Expr) :-
    Expr =:= 1.

用法示例:

?- count([0, 2, 3, 0], is_one, Count).
Count = 0.

?- count([1, 2, 3, 1], is_one, Count).
Count = 2.

另一种(相当肮脏的)方法是使用include / 3和length / 2:

count(List, Condition, Count) :-
    include(Condition, List, Filtered),
    length(Filtered, Count).

答案 1 :(得分:3)

让我们从您的代码开始并询问一些问题!

我在旁边添加了评论,显示了我预期的结果......

?- count([0,2,3,0], Count).
false                                 % bad: expected Count = 0
?- count([1,2,3,1], Count).
Count = 2                             % ok
?- count([1,2,3], Count).
false                                 % bad: expected Count = 1

如果我的期望与您的期望匹配,则代码的最小修复很少:只需移除目标N > 0

count([], 0).
count([H|T], N) :-
   count(T, X),
   (  H =:= 1
   -> N is X+1
   ;  N is X
   ).

让我们再次运行查询:

?- count([0,2,3,0], Count).
Count = 0                             % was “false”, now ok
?- count([1,2,3,1], Count).
Count = 2                             % was ok, still is ok
?- count([1,2,3], Count).
Count = 1.                            % was “false”, now ok

底线:只要最后一个列表项不等于1,原始代码就会失败。

答案 2 :(得分:2)

试试这个:

count([],0).
count([1|T],N) :- count(T,N1), N is N1 + 1.
count([X|T],N) :- X \= 1, count(T,N).

答案 3 :(得分:2)

由于您已经选择使用(;)/ 2 - if-then-else,因此您可能会发现以下if_/3变体很有趣:

list_1s(L,X) :-
   length(L,Len),
   list_1s_(L,X,0,Len).

list_1s_([],X,X,0).
list_1s_([Y|Ys],X,Acc0,Len1) :-
   if_(Y=1, Acc1 is Acc0+1, Acc1 is Acc0),
   Len0 is Len1-1,
   list_1s_(Ys,X,Acc1,Len0).

调用谓词list_1s / 2中的目标长度/ 2与实际关系list_1s_ / 4的第4个参数一起用于确保如果使用第一个参数调用谓词,则以公平的方式列出结果列表变数。 list_1s_ / 4的第三个参数是一个累加器,用于计算从零开始的1的数量,以使谓词尾递归。因此,如果列表为空,则list_1s_ / 4的第2和第3个参数相等。现在让我们看一些示例查询。在数字方向列表中,谓词产生了预期的结果并且确定性地成功(它不会使不必要的选择点打开,在单个答案后不需要按;):

?- list_1s([],X).
X = 0.

?- list_1s([1,2,3],X).
X = 1.

?- list_1s([1,2,3,1],X).
X = 2.

?- list_1s([0,2,3,0],X).
X = 0.

在列出方向的数字中,对于任何给定的数字,有无限多的列表,并且如上所述,它们以公平的方式列出,即,在移动到长度n之前列出长度为n的列表的所有可能性1:

?- list_1s(L,0).
L = [] ;                            % <- empty list
L = [_G386],                        % <- length 1
dif(_G386, 1) ;
L = [_G442, _G445],                 % <- length 2
dif(_G442, 1),
dif(_G445, 1) ;
L = [_G498, _G501, _G504],          % <- length 3
dif(_G498, 1),
dif(_G501, 1),
dif(_G504, 1) ;
.
.
.

?- list_1s(L,1).
L = [1] ;                           % <- length 1
L = [1, _G404],                     % <- length 2
dif(_G404, 1) ;
L = [_G401, 1],                     % <- length 2
dif(_G401, 1) ;
L = [1, _G460, _G463],              % <- length 3
dif(_G460, 1),
dif(_G463, 1) ;
L = [_G457, 1, _G463],              % <- length 3
dif(_G457, 1),
dif(_G463, 1) ;
L = [_G457, _G460, 1],              % <- length 3
dif(_G457, 1),
dif(_G460, 1) ;
.
.
.

最常见的查询是以公平的方式列出结果:

?- list_1s(L,X).
L = [],                             % <- empty list
X = 0 ;
L = [1],                            % <- length 1
X = 1 ;
L = [_G413],                        % <- length 1
X = 0,
dif(_G413, 1) ;
L = [1, 1],                         % <- length 2
X = 2 ;
L = [1, _G431],                     % <- length 2
X = 1,
dif(_G431, 1) ;
L = [_G428, 1],                     % <- length 2
X = 1,
dif(_G428, 1) ;
.
.
.