Prolog - 计算数字在列表中出现的次数

时间:2017-11-14 00:35:13

标签: prolog

所以我对Prolog很新。我需要编写一个代码段,无论嵌套有多深,都会计算列表中出现的任何数字的所有时间。例如,     countNums([1,a,2,[3,b,4,[5,c,6]]],N) 应该返回N = 6

这是我的代码:

listp([]).                        %define listp's
listp([H|T]).
countNums([],0).                    %base case for empty list
countNums([H|T], N) :- listp(H).    %check if head is a list
countNums([[H|T]|T1], N) :- countNums([H|T], N).
%check if head is not a number, if not do func with tail and dont increment
%if it is, do func with tail and increment N
countNums([H|T], N):- (
    number(H) ->
    countNums(T, N1),
    N is N1+1;
    countNums(T, N1),
    N is N1).

所以,如果列表只是一个级别的列表(即[1,2,3]),这个代码将起作用,但如果它遇到任何新的级别(即[1,2,[3]]),它失败并退出。

我知道很多这段代码可能没有意义,但也许你们好的人可以帮助我吗?

1 个答案:

答案 0 :(得分:1)

试试这个:

countNums([],0). %1
countNums([H|T],N) :- number(H), !, countNums(T,N1), N is N1 + 1. %2
countNums([[H|T1]|T2],N) :- !, countNums([H|T1],N1), countNums(T2,N2), N is N1 + N2. %3
countNums([_|T],N) :- countNums(T,N). %4

要将其分解,谓词(1)是空列表的基本情况;谓词(2)在列表上匹配,如果number(H)的第一个目标成功,那么我们找到了一个数字,所以没有必要尝试任何其他谓词,因此切割(! ); (3)匹配当我们有一个列表,其中列表的头部也是一个列表,并且在这种情况下,我们不想尝试剩余的谓词,所以我们现在递归到头列表并计算尾巴,然后将两个结果加在一起;最后我们用(4)表示头部既不是数字也不是列表,所以我们只是跳过头部并计算尾部。

然后:

?- countNums([1, a, 2, [3, b, 4, [5, c, 6]]], N), write(N), nl, fail.

给了我这个:

6
No.

仅限一个解决方案,因fail而失败。