如何制作“2个列表的交集”谓词?

时间:2013-11-06 14:53:37

标签: prolog

我正在尝试制作两个列表的交集(即列表C包含那些,只有那些在A和B中的元素),但据我所知,我得到了2个列表的分离+任何数量的元素下进行。

打算像以下一样工作:

  • 如果X在C中,则它必须同时在A和B中。(我相信X应该迭代C的所有成员!?)
  • 谓词:d(A,B,C) :- (member(X,D)->member(X,A),member(X,B)).

你能告诉我:我的句子和谓词不相同还是我犯了另一个错误?

示例:

?- [user].

|: d(A,B,C) :- (member(X,D)->(member(X,A),member(X,B))).
|: % user://1 compiled 0.01 sec, 612 bytes
true.

?- d([a,b],[b,c],C)
|    .
C = [b|_G21] .

?- d([a,b],[b,c],[b]).
true .

3 个答案:

答案 0 :(得分:1)

删除了重复项的O(NlogN)解决方案:

% untested
intersection(A, B, O) :-
    sort(A, AS),
    sort(B, BS),
    intersection1(AS, BS, O).

intersection1(A, B, O) :-
    (    A = [AH|AT],
         B = [BH|BT]
    ->   (    AH == BH
         ->   O = [AH|OT],
              intersection1(AT, BT, OT)
         ;    (    AH @< BH
              ->   intersection1(AT, B, O)
              ;    intersection1(A, BT, O) ) )
     ;   O = [] ).

答案 1 :(得分:1)

我喜欢@salva提出的解决方案,虽然我会做一个更简单的排序和合并,但却放弃了任何不匹配的东西:

intersect( As , Bs , Cs ) :-
  sort( As , SortedAs ) ,
  sort( Bs , SortedBs ) ,
  merge( SortedAs , SortedBs , Cs )
  .

merge( []     , []     , [] ).
merge( []     , [_|_]  , [] ).
merge( [_|_]  , []     , [] ).
merge( [C|As] , [C|Bs] , [C|Cs] ) :-          merge(    As ,     Bs  , Cs ) .
merge( [A|As] , [B|Bs] , Cs     ) :- A @< B , merge(    As  , [B|Bs] , Cs ) .
merge( [A|As] , [B|Bs] , Cs     ) :- A @> B , merge( [A|As] ,    Bs  , Cs ) .

答案 2 :(得分:0)

你的谓词d / 3应该用建设性术语重新表述,因为Prolog它是'一次性'元组'关系语言:

d(X,Y,Z) :- findall(E, (member(E,X), memberchk(E,Y)), Z).

产生

?- d([a,b],[b,c],C).
C = [b].

memberchk / 2它是member / 2的确定性版本,用于枚举所有X'元素。如果用member替换memberchk并尝试用包含重复项的列表调用d / 3,你可以更好地理解差异。

findall / 3这是更简单的'所有解决方案'列表构造函数。