编写一个包含三个参数的递归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/3
和dif/3
来排除重复项:
我们基于元谓词tcountd/3
、Prolog lambda和memberd_t/3
来定义common/3
:
让我们运行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
. %