编写一个名为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.
答案 0 :(得分:2)
:- use_module(library(clpfd)).
首先,我们定义meta-predicate tcountd/3
以便折扣重复的列表项。
tcount/3
与tcount/3
类似,但使用tfilter/3
和dif/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).
我们根据meta-predicate common/3
,Prolog lambdas和memberd_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
. %