编写一个名为common的三个参数的递归Prolog谓词,它返回属于两个列表的元素数

时间:2014-06-26 21:26:25

标签: prolog

编写一个名为common的三个参数的递归Prolog谓词,它返回属于两个列表的元素数。        例如:

   ?- common ( [a, b, c, k, h], [b,c,d,e], N).
   N=2.

   ?- common ( [b, a, c, d], [a, b, c, d, e] ,  N).
   N=4.

3 个答案:

答案 0 :(得分:2)

保留

:- use_module(library(clpfd)).

首先,我们定义 tcountd/3以便折扣重复的列表项。
tcount/3tcount/3类似,但使用tfilter/3dif/3排除重复项:

:- meta_predicate tcountd(2,?,?).
tcountd(P_2,List,Count) :-
   list_tcountd_pred(List,Count,P_2).

:- meta_predicate list_tcountd_pred(?,?,2).
list_tcountd_pred([]     ,0, _ ).
list_tcountd_pred([X|Xs0],N,P_2) :-
   if_(call(P_2,X), (N #= N0+1, N0 #>= 0), N = N0),
   tfilter(dif(X),Xs0,Xs),
   list_tcountd_pred(Xs,N0,P_2).

我们根据 common/3Prolog lambdasmemberd_t/3定义tcountd/3

common(Xs,Ys,N) :-
   tcountd(Ys+\X^memberd_t(X,Ys),Xs,N).

让我们运行OP提供的示例查询:

?- common([a,b,c,k,h],[b,c,d,e],N).
N = 2.

?- common([b,a,c,d],[a,b,c,d,e],N).
N = 4.

由于common/3 单调,我们也可以通过非地面查询获得声音答案!考虑:

?- common([A,B],[X,Y],N).
  N = 1,     A=B ,                         B=X
; N = 2,               A=X ,                         B=Y , dif(X,Y)
; N = 1,               A=X ,           dif(B,X), dif(B,Y)
; N = 1,     A=B ,                                   B=Y , dif(X,Y)
; N = 2,                         A=Y ,     B=X ,           dif(X,Y)
; N = 1,                         A=Y , dif(B,X), dif(B,Y), dif(X,Y)
; N = 0,     A=B ,                     dif(B,X), dif(B,Y)
; N = 1,           dif(A,X), dif(A,Y),     B=X
; N = 1,           dif(A,X), dif(A,Y),               B=Y , dif(X,Y)
; N = 0, dif(A,B), dif(A,X), dif(A,Y), dif(B,X), dif(B,Y).

答案 1 :(得分:0)

使用intersection/3内置功能:

common(A, B, N) :-
    intersection(A, B, C),
    length(C, N).

试运行:

?- common([a, b, c, k, h], [b,c,d,e], N).
N = 2.

?- common([b, a, c, d], [a, b, c, d, e],  N).
N = 4.

请注意,"普通"之间没有空格。和#34;("在查询中。这很重要。问题中陈述的查询("普通""(")之间的空格将给出语法错误。

答案 2 :(得分:0)

这是一种方法,假设您要确保结果是(唯一项)而不是(允许重复项):

set_intersection( Xs, Ys, Zs ) :- % to compute the set intersection,
   sort(Xs,X1) ,                  % - sort the 1st set, removing duplicates (so that it's a *set* rather than a *bag* ) ,
   sort(Ys,Y1) ,                  % - sort the 2nd set, removing duplicates (so that it's a *set* rather than a *bag* ) ,
   common( Xs , Ys , Zs )         % - merge the two now-ordered sets, keeping only the common items
   .

common( Xs , Ys , [] ) :-
  ( Xs=[] ; Ys=[] ) ,
  ! . 
common( [X|Xs] , [X|Ys] , [X|Zs] ) :-
  common( Xs , Ys , Zs ) .

另一种更简单的方法:

set_intersection( Xs , Ys , Zs ) :-
  set_of(Z,(member(Z,Xs),member(Z,Ys)),Zs)
  .

另一种方式:

set_intersection( Xs , Ys , Zs ) :-       % compute the set intersection by
  set_intersectin( Xs , Ys , [] , Zs ) .  % invoking the worker predicate

set_intersection( []     , _  , Zs , Zs ) .  % when we run out of Xs, we're done.
set_intersection( [X|Xs] , Ys , Ts , Zs ) :- % otherwise,
  member(X,Ys) ,                             % if X is a member of Ys,
  \+ member(X,Ts) ,                          % and we don't yet have an X,
  set_intersection( Xs , Ys , [X|Ts] , Zs )  % add X to the accumulator and recurse down
  .                                          %