我正在Prolog中编写一个程序,用于计算列表中第一个值的不间断次数。
所以,repetitions(N, [a,a,a,a,a,b,c,a])
,程序将返回N = 5
。
这是我的代码到目前为止的样子:
repetitions(A,[]).
repetitions(A,[A|T]) :- repetitions(A,[_|T]), A is 1+A.
repetitions(A,[_|T]) :- repetitions(A,[A|T]).
答案 0 :(得分:4)
以下是关系版本:
repetitions(N, [First|Rest]) :- phrase(repetitions_(First, 1, N), Rest). repetitions_(_, N, N) --> []. repetitions_(First, N0, N) --> [First], { N1 #= N0 + 1 }, repetitions_(First, N1, N). repetitions_(First, N, N) --> [Other], { dif(First, Other) }, ... . ... --> [] | [_], ... .
测试用例按要求运行:
?- repetitions(N, [a,a,a,a,a,b,c,a]). N = 5 ; false.
此外,我们也可以在其他方向中使用它。
例如,一般包含3个元素的列表:
?- Ls = [A,B,C], repetitions(N, Ls). Ls = [C, C, C], A = B, B = C, N = 3 ; Ls = [B, B, C], A = B, N = 2, dif(B, C) ; Ls = [A, B, C], N = 1, dif(A, B) ; false.
所有可能的答案如何,通过迭代深化进行了相当的列举:
?- length(Ls, _), repetitions(N, Ls). Ls = [_8248], N = 1 ; Ls = [_8248, _8248], N = 2 ; Ls = [_8734, _8740], N = 1, dif(_8734, _8740) ; Ls = [_8248, _8248, _8248], N = 3 ; Ls = [_8740, _8740, _8752], N = 2, dif(_8740, _8752) ; etc.
它是逻辑程序的一个主要吸引力,它们通常可用于多个方向。
有关我用来实现此一般性的机制的详细信息,请参阅dcg,prolog-dif和clpfd。
我们也可以用它来回答以下问题
列表看起来像什么,第一个元素有3次重复?
示例:
?- repetitions(3, Ls). Ls = [_2040, _2040, _2040] ; Ls = [_2514, _2514, _2514, _2532], dif(_2514, _2532) ; Ls = [_2526, _2526, _2526, _2544, _2550], dif(_2526, _2544) ; Ls = [_2538, _2538, _2538, _2556, _2562, _2568], dif(_2538, _2556) .
这只需要在上面的解决方案中添加一个进一步的约束。我把这作为一个简单的练习。
答案 1 :(得分:4)
这是一个基于DCG的解决方案,有点像@mat's的变种:
repetitions_II(N, [X|Cs]) :-
phrase( ( reps(X, N), no(X) ), [X|Cs]).
no(X) -->
( [] | [Y], {dif(X,Y)}, ... ).
reps(_X, 0) -->
[].
reps(X, N0) -->
[X],
{ N0 #> 0, N1 #= N0-1 },
reps(X, N1).
两个值得注意的差异:
1mo)维持计数器没有任何区别。因此,对数量的约束可以帮助改善终止。一个完美的clpfd实现将(或者更应该)以相似的效率实现这一点。
2do)结尾no//1
基本上以纯粹的方式编码\+[X]
。
这个解决方案的缺点是它仍然会产生剩余的选择点。要摆脱这些,需要一些更多的手动编码:
:- use_module(library(reif)).
repetitions_III(N, [X|Xs]) :-
reps([X|Xs], X, N).
reps([], _, 0).
reps([X|Xs], C, N0) :-
N0 #>= 0,
if_(X = C, ( N1 #= N0-1, reps(Xs, C, N1) ), N0 = 0 ).
答案 2 :(得分:2)
使用CLPFD的另一种接近你目前所做的方法:
:- use_module(library(clpfd)).
repetitions(N,[H|T]):-repetitions(N,[H|T],H).
repetitions(0,[],_).
repetitions(0,[H|_],H1):-dif(H,H1).
repetitions(N,[H|T],H):-repetitions(N1 ,T, H), N #= N1+1.
示例:
?- repetitions(A,[a,a,a,a,a,b,c,a]).
A = 5 ;
false.
?- repetitions(2,[a,Y]).
Y = a.
?- repetitions(N,[a,a|_]).
N = 2 ;
N = 2 ;
N = 3 ;
N = 3 ;
N = 4 ;
N = 4 ;
N = 5 ;
N = 5 ;
N = 6 ;
N = 6 ....and goes on
答案 3 :(得分:1)