List 检查两个列表是否有公共元素

List 检查两个列表是否有公共元素,list,prolog,List,Prolog,基本上,我有一个称为common_elements(List1,List2)的谓词,这个谓词的目的是检查List1是否至少有一个属于List2的元素 例如: ?- common_elements([1,2,3,4,5,6],[6]). true. ?- common_elements([1,2,3],[2]). true. ?- common_elements([1,2,3],[6]). false. ?- common_elements([P1,P2,P3,P4,P5,P6],[P7,P

基本上,我有一个称为common_elements(List1,List2)的谓词,这个谓词的目的是检查List1是否至少有一个属于List2的元素

例如:

?- common_elements([1,2,3,4,5,6],[6]).
true.

?- common_elements([1,2,3],[2]).
true.

?- common_elements([1,2,3],[6]).
false.

?- common_elements([P1,P2,P3,P4,P5,P6],[P7,P8,P6]).
true.
?- common_elements([1,2,3],[2]).
true.

?- common_elements([1,2,3],[6]).
false.

?- common_elements([P1,P2,P3,P4,P5,P6],[P7,P8,P6]).
P1 = P7.

所以对于数字,这很有效,但是如果我输入变量,它会统一变量,而不是检查它们是否在第二个列表中

例如:

?- common_elements([1,2,3,4,5,6],[6]).
true.

?- common_elements([1,2,3],[2]).
true.

?- common_elements([1,2,3],[6]).
false.

?- common_elements([P1,P2,P3,P4,P5,P6],[P7,P8,P6]).
true.
?- common_elements([1,2,3],[2]).
true.

?- common_elements([1,2,3],[6]).
false.

?- common_elements([P1,P2,P3,P4,P5,P6],[P7,P8,P6]).
P1 = P7.

所以,正如你所看到的,对于数字,它工作得很好,但由于某种原因,如果类型变量,它将它们统一起来,而不是仅仅比较它们,而且似乎你不明白为什么

节目:

common_elements(L1,L2) :- common_elements(L1,L2,[]).

common_elements([],_,AC) :- length(AC,C),
                            C >= 1.

common_elements([P|_],L2,AC) :- member(P,L2),!,
                                append(AC,[P],NAC),
                                common_elements([],L2,NAC).

common_elements([P|R],L2,AC) :- \+ member(P,L2),!,
                                common_elements(R,L2,AC).


成员/2
谓词将执行统一。事实上,例如:

?- member(P1, [P2]).
P1 = P2.
您可以利用来避免统一,因此:

如果
Term1
等同于
Term2
,则为True。变量仅与共享变量相同

所以我们在这里可以做的是检查一个变量是否与另一个变量等价:

membereq(X, [H|_]) :-
    X == H.
membereq(X, [_|T]) :-
    membereq(X, T).
因此,我们可以检查:

common_elements([H|_], L2) :-
    membereq(H, L2).
common_elements([_|T], L2) :-
    common_elements(T, L2).
然后,这将回答以下问题:

?- common_elements([1,2,3,4,5,6],[6]).
true ;
false.

?- common_elements([1,2,3,4,5,6],[6]).
true ;
false.

?- common_elements([1,2,3],[2]).
true ;
false.

?- common_elements([1,2,3],[6]).
false.

?- common_elements([P1,P2,P3,P4,P5,P6],[P7,P8,P6]).
true ;
false.

成员/2
谓词将执行统一。事实上,例如:

?- member(P1, [P2]).
P1 = P2.
您可以利用来避免统一,因此:

如果
Term1
等同于
Term2
,则为True。变量仅与共享变量相同

所以我们在这里可以做的是检查一个变量是否与另一个变量等价:

membereq(X, [H|_]) :-
    X == H.
membereq(X, [_|T]) :-
    membereq(X, T).
因此,我们可以检查:

common_elements([H|_], L2) :-
    membereq(H, L2).
common_elements([_|T], L2) :-
    common_elements(T, L2).
然后,这将回答以下问题:

?- common_elements([1,2,3,4,5,6],[6]).
true ;
false.

?- common_elements([1,2,3,4,5,6],[6]).
true ;
false.

?- common_elements([1,2,3],[2]).
true ;
false.

?- common_elements([1,2,3],[6]).
false.

?- common_elements([P1,P2,P3,P4,P5,P6],[P7,P8,P6]).
true ;
false.

使用内置,如您标记的SWI和
ordset
是不受欢迎的

:- use_module(library(ordsets)).

common_elements(A, B) :-
    sort(A, AS), % can omit if using sorted A list
    sort(B, BS), % can omit if using sorted B list
    ord_intersect(As, Bs).
一些例子:

t1 :-
    common_elements([a, b, c], [d, e, f]).

t2 :-
    common_elements([a, b, c], [c, d, e]).

t3 :-
    common_elements([a, b, c], [_A, _B, _C]).

t4 :-
    common_elements([a, b, C], [d, e, C]).

t5 :-
    common_elements([a, b, _C], [d, e, _F]).

tests :-
    \+ t1,
         t2,
    \+ t3, 
         t4, 
    \+ t5.

注意:使用
sort/2
而不是
list\u to\u set/2
,因为后者保留了变量。此外,使用
ord_intersect/2
over
intersection/3
,因为后者可能会产生意外的结果。如果您使用许多集合操作,您可能会发现在整个过程中使用有序列表(
ordset
)是值得的。

使用内置的,因为您标记了SWI和
ordset

:- use_module(library(ordsets)).

common_elements(A, B) :-
    sort(A, AS), % can omit if using sorted A list
    sort(B, BS), % can omit if using sorted B list
    ord_intersect(As, Bs).
一些例子:

t1 :-
    common_elements([a, b, c], [d, e, f]).

t2 :-
    common_elements([a, b, c], [c, d, e]).

t3 :-
    common_elements([a, b, c], [_A, _B, _C]).

t4 :-
    common_elements([a, b, C], [d, e, C]).

t5 :-
    common_elements([a, b, _C], [d, e, _F]).

tests :-
    \+ t1,
         t2,
    \+ t3, 
         t4, 
    \+ t5.

注意:使用
sort/2
而不是
list\u to\u set/2
,因为后者保留了变量。此外,使用
ord_intersect/2
over
intersection/3
,因为后者可能会产生意外的结果。如果您使用许多集合操作,您可能会发现在整个过程中使用有序列表(
ordset
)是值得的。

因为
member/2
将统一元素。因为
member/2
将统一元素。