【问题标题】:checking if two lists have common elements检查两个列表是否有共同的元素
【发布时间】:2020-04-20 15:07:21
【问题描述】:

所以基本上,我有一个谓词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(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).

【问题讨论】:

  • 因为member/2会统一元素。

标签: list prolog


【解决方案1】:

member/2 谓词将执行统一。确实,例如:

?- member(P1, [P2]).
P1 = P2.

您可以使用==/2 来避免统一,因此:

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

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

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】:

    使用内置函数,因为您已标记 SWI 并且 ordsets 未被充分重视

    :- 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_to_set/2,因为后者会保留变量。此外,使用ord_intersect/2 而不是intersection/3,因为后者会产生意想不到的结果。如果您使用许多集合操作,您可能会发现在整个过程中使用有序列表 (ordsets) 是值得的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-16
      • 1970-01-01
      • 1970-01-01
      • 2014-07-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多