在Prolog中没有重复元素的两个列表的交集

时间:2015-07-26 10:21:30

标签: list prolog duplicates

我需要编写一个程序来查找两个列表的交集。我不能使用剪切,结果列表中不应该有任何重复的元素。

这是我的代码:

intersection([],_,[]).
intersection([X|Xs],Y,[X|Zs]) :-
    member(X,Y),
    intersection(Xs,Y,Zs).
intersection([_|Xs],Y,Zs) :-
    intersection(Xs,Y,Zs).

当我运行以下查询时,我得到以下答案:

?- intersection([a,b,c,a],[a,v,c],L).
L = [a, c, a] ;
L = [a, c] ;            % <---------- this is only answer I want to get
L = [a, a] ;
L = [a] ;
L = [c, a] ;
L = [c] ;
L = [a] ;
L = [].

我该怎么办?我想得到L = [a,c]而没有别的......你能帮忙吗?

5 个答案:

答案 0 :(得分:6)

my answer的相关问题“Intersection and union of 2 lists”中,我提出了逻辑纯谓词list_list_intersectionSet/3。它应该符合您的要求T!

这是list_list_intersectionSet/3的刷新版本,它基于:

我们走了:

list_list_intersectionSet([]     ,_ ,[]).
list_list_intersectionSet([A|As0],Bs,Cs0) :-
   if_(memberd_t(A,Bs), Cs0 = [A|Cs], Cs0 = Cs),
   tfilter(dif(A),As0,As), 
   list_list_intersectionSet(As,Bs,Cs).

让我们看看它的实际效果!

?- list_list_intersectionSet([a,b,c,a],[a,v,c],L).
L = [a,c].

答案 1 :(得分:3)

如果通过&#34;结合&#34;你的意思是&#34;十字路口&#34;,你应该看一下谓词library(lists)的SWI-Prolog intersection/3中的实现。它包含剪辑,但如果你不介意所有选择点,你可以将它们排除在外。

用它:

?- intersection([a,b,c,a],[a,v,c],I).
I = [a, c, a].

当然,即使在库谓词中,这也不起作用,因为您需要使用当前定义 sets 。 (如果只有第一个参数是一个集就足够了。)

您可以使用sort/2谓词创建集合:如果第一个参数是具有重复的列表,则第二个参数将是不重复的排序列表,例如:

?- sort([a,b,c,a], S1), intersection(S1, [a,v,c], I).
S1 = [a, b, c],
I = [a, c].

或者也许:

?- sort([a,b,c,a], S1), intersection(S1, [a,v,c,c,a,c], I).
S1 = [a, b, c],
I = [a, c].

?- sort([a,b,c,a,b,c,a,b,c], S1), intersection(S1, [a,v,c,c,a,c], I).
S1 = [a, b, c],
I = [a, c].

如果您对两个参数进行排序,则可以使用ord_intersection/3中的library(ordsets)oset_int/3实现。

?- sort([a,b,c,a], S1), sort([a,v,c,c,a,c], S2), ord_intersection(S1, S2, I).
S1 = [a, b, c],
S2 = [a, c, v],
I = [a, c].

重要的是,oset_int/3在其实施中不使用任何削减。然而,它假设第一个和第二个参数是按"standard order of terms"排序的元素列表,没有重复,如sort/2所做。

如果由于某种原因你不想使用sort/2,你可以使用累加器并在将元素带到交叉点之前检查它:

my_intersection(Xs, Ys, Zs) :-
    my_intersection_1(Xs, Ys, [], Zs).
my_intersection_1([], _, Zs, Zs).
my_intersection_1([X|Xs], Ys, Zs0, Zs) :-
    member(X, Ys), \+ member(X, Zs0),
    my_intersection_1(Xs, Ys, [X|Zs0], Zs).
my_intersection_1([_|Xs], Ys, Zs0, Zs) :-
    my_intersection_1(Xs, Ys, Zs0, Zs).

当然,结果中元素的顺序现在将颠倒过来。如果这不是你所说的&#34;结合&#34;,你可以例如将my_intersection_1/4的前两个条款重写为:

my_intersection_1([], _, _, []).
my_intersection_1([X|Xs], Ys, Zs0, [X|Zs]) :-
    member(X, Ys), \+ member(X, Zs0),
    my_intersection_1(Xs, Ys, [X|Zs0], Zs).

答案 2 :(得分:3)

之前显示的list_list_intersectionSet/3 限制交叉口中的商品订单:

?- list_list_intersectionSet([a,b],[a,b], [a,b]).
true.

?- list_list_intersectionSet([a,b],[a,b], [b,a]).
false.

在这个答案中,我们解除了这个限制......保留 决定论(对于地面案例)!

首先,我们使用Prolog lambdas定义none_intersect/2 maplist/2

none_intersect(As,Bs)声明As中的所有成员都与Bs中的所有成员不同。

:- use_module(library(lambda)).

none_intersect(As,Bs) :-
   maplist(\A^maplist(dif(A),Bs),As).

接下来,我们定义intersection_of_and/3 ---基于none_intersect/2(上面定义), tpartition/4和具体术语相等(=)/3

intersection_of_and([],As,Bs) :-
   none_intersect(As,Bs).
intersection_of_and([X|Xs],As0,Bs0) :-
   tpartition(=(X),As0,[_|_],As),        % [_|_] = [X|_]
   tpartition(=(X),Bs0,[_|_],Bs),        % [_|_] = [X|_]
   intersection_of_and(Xs,As,Bs).

intersection_of_and(Xs,As,Bs)表示

  • AsBs中出现的所有项目也会出现在Xs(第一条)中,
  • Xs中的所有项目都在AsBs中出现至少一次(第二个子句),
  • 且列表Xs不包含任何重复项。

intersection_of_and/3使用特定参数来启用第一个参数索引。

最后,我们定义list_list_intersection/3,它具有OP使用的参数顺序:

list_list_intersection(As,Bs,Xs) :-
   intersection_of_and(Xs,As,Bs).

让我们运行一些查询!首先,赏金提供者建议的查询:

?- list_list_intersection([a,b],[a,b], [b,a]).
true.

接下来,类似的查询在3个列表中有3个不同的项目,有3个不同的顺序:

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

如果某些x仅出现在第一个/第二个列表中会怎样?

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

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

如果某个项目在第一个/第二个列表中出现两次怎么办?

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

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

最后,如果交集包含重复项怎么办? 交叉点包含重复项...

?- list_list_intersection([a,b,c],[b,a,c], [c,c,a,b]).
false.                                     % as expected

答案 3 :(得分:0)

似乎这样的事情很简单:

intersection( Xs , Ys , Zs ) :-
  sort(Xs,X1)     , % order and de-dupe the 1st list so as to produce a set
  sort(Ys,Y1)     , % order and de-dupe the 2nd list so as to produce a set
  merge(Xs,Ys,Zs)   % merge the two [ordered] sets to produce the result
  .                 % easy!

merge( []     , []     , []     ) .
merge( []     , [_|_]  , []     ) .
merge( [_|_]  , []     , []     ) .
merge( [X|Xs] , [Y|Ys] , [X|Zs] ) :- X =  Y , merge(    Xs  ,    Ys  , Zs ) .
merge( [X|Xs] , [Y|Ys] , Zs     ) :- X <  Y , merge(    Xs  , [Y|Ys] , Zs ) .
merge( [X|Xs] , [Y|Ys] , Zs     ) :- X >  Y , merge( [X|Xs] ,    Ys  , Zs ) .

或者甚至只是这种[非常高效的]单线:

intersection( Xs , Ys , Zs ) :- setof(Z,(member(Z,Xs),member(Z,Ys)),Zs).

答案 4 :(得分:0)

这可以通过简单的集理论来解决:

    intersection(A,B,AnB):-
        subtract(A,B,AminusB),
        subtract(A,AminusB,K),
        sort(K,AnB).

对于查询:

   ?- intersection([a,b,c,a],[a,v,c],L).

输出

    L = [a, c].

没有更多答案。