Prolog:搜索列表中的2个元素是否同等

时间:2017-11-14 21:57:52

标签: list prolog prolog-dif

我是Prolog的新手而不是母语人士,所以如果你不理解我,我很抱歉。

我的问题是如何才能找到列表中的ab是否同等?

例如,[a,a,b,b]应该给我true,但如果其中任何一个看起来比另一个更多,那么它应该给false。例如:[a,a,a,b,b]

有人能帮帮我吗?这是我到目前为止所知道的,但我知道这是错误的,但我正在努力。

count(N,[],0).
count(N,[N|T],U) :-
   !,
   count(N,T,U1),
   U is U1+1.
count(N,[H|T],U) :-
   count(N,T,U).

occurrences([],[]).
occurrences([H|T],[[H,X]|Y]) :-
   count(H,[H|T],X),
   occurrences(T1,Y).

4 个答案:

答案 0 :(得分:2)

以下是if_/3=/3的事件/ 5的更紧凑版本:

occurrences([],_A,_B,N,N).
occurrences([H|T],A,B,N0,M0) :-
   elem_x_count_(H,A,N1,N0),
   elem_x_count_(H,B,M1,M0),
   occurrences(T,A,B,N1,M1).

elem_x_count_(E,X,New,Old) :-
   if_(E=X, New is Old+1, New=Old).

在此版本中,只有一个递归规则使用elem_x_count_ / 4来增加相应的计数器参数(如果列表的头部分别与AB匹配,或者保持不变。调用谓词保持不变:

occurrences(List,A,B) :-
   dif(A,B),
   occurrences(List,A,B,0,0).

occurrences(List) :-
   occurrences(List,a,b,0,0).

这样,如果所有三个参数都是基础的话,谓词就会成功确定(不需要在;之后按true,因为没有选择点保持打开状态)。以下是旧版本中带有出现次数/ 3的示例查询:

?- occurrences([a,a,b,b],a,b).
true.

另一个区别是dif / 2约束的数量较少。例如:

?- occurrences([a,a,b,b,c,c,d],X,Y).
X = a,
Y = b ;
X = a,
Y = c ;
X = b,
Y = a ;
X = c,
Y = a ;
X = b,
Y = c ;
X = c,
Y = b ;
dif(X, d),
dif(X, c),
dif(X, b),
dif(X, a),
dif(X, Y),
dif(Y, d),
dif(Y, c),
dif(Y, b),
dif(Y, a).

此查询的最后一个解决方案与我以前的版本不同。它描述了相同的结果,但在另一个版本中出现两次的所有差异现在只出现一次。其他示例查询产生相同的答案。

答案 1 :(得分:1)

如果第二个和第三个参数在第一个参数的列表中经常出现,则可以编写谓词出现次数/ 5。第4和第5个参数是相应的计数器。然后谓词出现次数/ 1是调用谓词:

occurrences(List) :-
   occurrences(List,a,b,0,0).

occurrences([],_A,_B,N,N).       
occurrences([A|Xs],A,B,N0,M) :-  
   N1 is N0+1,                   
   occurrences(Xs,A,B,N1,M).     
occurrences([B|Xs],A,B,N,M0) :-
   M1 is M0+1,
   occurrences(Xs,A,B,N,M1).
occurrences([X|Xs],A,B,N,M) :-
   dif(A,X),
   dif(B,X),
   occurrences(Xs,A,B,N,M).

从0开始计数器,并且根据列表的头部等于AB,相应的计数器会递增,或者如果磁头与两者不同,则不会递增计数器。现在让我们看看给出示例的结果:

?- occurrences([a,a,b,b]).
true ;
false.

?- occurrences([a,a,a,b,b]).
false.

但是,我认为使用谓词出现/ 3可以指定这两个元素会更有用:

occurrences(List,A,B) :-
   dif(A,B),                     
   occurrences(List,A,B,0,0).    

然后您的示例查询将如下所示:

?- occurrences([a,a,b,b],a,b).
true ;
false.

?- occurrences([a,a,a,b,b],a,b).
false.

您还可以询问哪些元素经常出现:

?- occurrences([a,a,b,b,c,c,d],X,Y).
X = a,
Y = b ;
X = a,
Y = c ;
X = b,
Y = a ;
X = c,
Y = a ;
X = b,
Y = c ;
X = c,
Y = b ;
dif(X, d),
dif(X, c),
dif(X, c),
dif(X, b),
dif(X, b),
dif(X, a),
dif(X, a),
dif(X, Y),
dif(Y, d),
dif(Y, c),
dif(Y, c),
dif(Y, b),
dif(Y, b),
dif(Y, a),
dif(Y, a).

最后一个解决方案对应于两个根本没有出现在列表中的元素,因为它们都经常出现,即0次。如果你想在另一个方向上使用谓词,也就是说,要询问哪些列表有两个给定元素经常出现,你必须在谓词时限制列表长度的目标前缀打电话,例如:

?- length(L,_),occurrences(L,a,b).
L = [] ;
L = [_G150],
dif(_G150, b),
dif(_G150, a) ;
L = [a, b] ;
L = [b, a] ;
L = [_G116, _G119],
dif(_G116, b),
dif(_G116, a),
dif(_G119, b),
dif(_G119, a) ;
L = [a, b, _G162],
dif(_G162, b),
dif(_G162, a) ;
L = [a, _G159, b],
dif(_G159, b),
dif(_G159, a) ;
L = [b, a, _G162],
dif(_G162, b),
dif(_G162, a) ;
.
.
.

答案 2 :(得分:0)

您可以在访问时从列表'尾部 - 它必须存在 - 中选择匹配元素,而不是计数。

递归基础案例将是您能想到的最简单的... 而select / 3是内置的,可以为您的问题提供真正紧凑的解决方案。

修改

嗯,代码很简单......

occurrences([],[]).
occurrences([H|T],R) :- select(H,T,U), occurrences(U,R).

注意:成功时,R将成为空列表

答案 3 :(得分:0)

你只有一个列表,所以一开始你的模式匹配会失败顺便说一下我会尝试这样做,我不会添加任何解释,这样你就可以自己弄清楚它是如何工作的。

count(List):-
  count(List,0,0).

count([],L,L).


count([H|T],L,R):-
  (   
   H == 'a' ->
      NewL is L + 1,
      count(T,NewL,R)
    )
     ;
   (
     H == 'b' ->
       NewRight is R + 1,
       count(T,L,NewRight)
    ).