我试图找出两个列表是否重叠。我想写的谓词 如果列表至少有两个共同的元素,则获取两个列表并返回true。
具有预期答案的示例查询:
?- overlap([13,14,15], [17,18,13,19]).
false.
?- overlap([13,14,15], [14,17,13,18,16]).
true.
然而,到目前为止,我只有一个元素可以工作。
member(M, [M|_]).
member(M, [_|T]) :-
member(M, T).
overlap(X, Y) :-
member(M, X),
member(M, Y).
?- overlap([a,b,c,d], [1,2,c,d]).
如何确保检查两个元素,而不只是一个?
答案 0 :(得分:4)
另一种非常接近您的代码的方法是确保两个成员不相同:
overlap(X, Y) :-
dif(A, B),
member(A, X), member(A, Y),
member(B, X), member(B, Y).
由于有评论要求采用更有效的方法,因此这是一种完全不同的方法,如this answer to a very similar question。
overlap(N, X, Y) :-
sort(Xs, SX),
sort(Ys, SY),
append(SX, SY, All), length(All, Len_all),
sort(All, Sorted), length(Sorted, Len_sorted),
Len_sorted =< Len_all - 2.
简单来说,由于sort也会删除所有重复项,因此您可以通过比较排序前后的长度来计算列表中重复项的数量。一旦以这种方式编写谓词,您还会注意到您可以稍微概括一下,因此它有两个参数:列表列表和非负整数,它是所有列表之间共享的元素数:
overlap_n(LL, N) :-
maplist(sort, LL, SLL), % sort all lists
append(SLL, All), length(All, Len_all),
sort(All, Sorted), length(Sorted, Len_sorted),
N is Len_all - Len_sorted.
您现在可以将原始问题表达为:
?- overlap_n([X, Y], N), N >= 2.
答案 1 :(得分:0)
如果你的Prolog有intersection / 3,那么较短的形式可能是:
overlap(X,Y) :- intersection(X,Y,[_,_|_]).
大型重叠列表效率低下。您的方法很容易纠正和扩展:
overlap(X,Y) :-
select(A,X,Rx), select(A,Y,Ry),
member(B,Rx), member(B,Ry).
我会在最后添加一个剪切以避免多种解决方案......