我需要编写一个程序来查找两个列表的交集。我不能使用剪切,结果列表中不应该有任何重复的元素。
这是我的代码:
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]
而没有别的......你能帮忙吗?
答案 0 :(得分:6)
在my answer的相关问题“Intersection and union of 2 lists”中,我提出了逻辑纯谓词list_list_intersectionSet/3
。它应该符合您的要求T!
这是list_list_intersectionSet/3
的刷新版本,它基于:
if_/3
,tfilter/3
,dif/3
和memberd_t/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.
在这个答案中,我们解除了这个限制......保留logical-purity 和决定论(对于地面案例)!
首先,我们使用Prolog lambdas定义none_intersect/2
和
meta-predicate 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
(上面定义),meta-predicate 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)
表示
As
和Bs
中出现的所有项目也会出现在Xs
(第一条)中,Xs
中的所有项目都在As
和Bs
中出现至少一次(第二个子句),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].
没有更多答案。