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



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

   ?- 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.

保持逻辑纯洁性!

:- use_module(library(clpfd)).

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

<>之前:- meta_predicate tcountd(2,?,?)。tcount d (P_2,列表,计数):-list_tcount d _pred(列表、计数、P_2)。: - meta_predicate list_tcount d _pred(?, ?, 2)。List_tcount d_pred([],0, _)。list_tcount d _pred ([X | Xs0], N, P_2): -if (call(P_2,X), (n# = N0+1, n#>= 0), N = N0), tfilter (dif (X)、Xs0 Xs) ,list_tcount d _pred (Xs, N0, P_2)。之前

我们基于元谓词tcountd/3、Prolog lambda和memberd_t/3来定义common/3:

<>之前共同的(x, y, N): -tcount d (y + X ^成员 d _t (X, y), X, 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).

使用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.

注意,查询中的"common"one_answers"("之间没有空格。这很重要。如您在问题中所述的查询("common"one_answers"(")之间有空格)将导致语法错误。

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

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
  .                                          %

最新更新