两个列表的交集和联合

时间:2012-03-08 08:56:16

标签: list prolog

我开始学习prolog(我使用SWI-prolog),我做了一个简单的练习,其中我有2个列表,我想计算他们的交集和联合。 这是我的代码非常好但我问自己是否有更好的方法来做,因为我不喜欢使用CUT operator

intersectionTR(_, [], []).
intersectionTR([], _, []).
intersectionTR([H1|T1], L2, [H1|L]):-
    member(H1, L2),
    intersectionTR(T1, L2, L), !.
intersectionTR([_|T1], L2, L):-
    intersectionTR(T1, L2, L).

intersection(L1, L2):-
    intersectionTR(L1, L2, L),
    write(L).


unionTR([], [], []).
unionTR([], [H2|T2], [H2|L]):-
    intersectionTR(T2, L, Res),
    Res = [],
    unionTR([], T2, L),
    !.
unionTR([], [_|T2], L):-
    unionTR([], T2, L),
    !.

unionTR([H1|T1], L2, L):-
    intersectionTR([H1], L, Res),
    Res \= [],
    unionTR(T1, L2, L).
unionTR([H1|T1], L2, [H1|L]):-
    unionTR(T1, L2, L).

union(L1, L2):-
    unionTR(L1, L2, L),
    write(L).

请记住,我想只有1个结果,而不是多个结果(即使是正确的),所以运行代码:

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

应退出:

[1,2]
true.

而不是

[1,2]
true ;
[1,2]
true ;
etc...

同样必须对联合谓词有效。
正如我所说,我的代码工作得很好,但请提出更好的方法来做到这一点 感谢

8 个答案:

答案 0 :(得分:7)

另外,不确定为什么你死了反对削减,只要他们的删除不会改变代码的声明含义,根据你的链接。例如:

inter([], _, []).

inter([H1|T1], L2, [H1|Res]) :-
    member(H1, L2),
    inter(T1, L2, Res).

inter([_|T1], L2, Res) :-
    inter(T1, L2, Res).

test(X):-
        inter([1,3,5,2,4], [6,1,2], X), !.

test(X).
X = [1, 2].

在我调用代码的测试位中,我只是说做交集,但我只对第一个答案感兴趣。谓词定义本身没有削减。

答案 1 :(得分:6)

以下内容基于我的previous answerRemove duplicates in list (Prolog); 反过来,基本思想基于@false's answerProlog union for A U B U C

我想传达给你什么信息?

  • 你可以用合乎逻辑的纯度描述你想要的Prolog。
  • 使用if_/3(=)/3可以实现逻辑上纯粹的实现
    • 效率(仅在需要时留下选择点)
    • 和单调(关于泛化/专业化的逻辑上合理)。
  • @ false' s谓词if_/3(=)/3 的实现在内部使用元逻辑Prolog功能,但(从外部)表现逻辑纯粹的

以下list_list_intersection/3list_list_union/3的实施使用list_item_isMember/3中定义的list_item_subtracted/3list_list_union([],Bs,Bs). list_list_union([A|As],Bs1,[A|Cs]) :- list_item_subtracted(Bs1,A,Bs), list_list_union(As,Bs,Cs). list_list_intersection([],_,[]). list_list_intersection([A|As],Bs,Cs1) :- if_(list_item_isMember(Bs,A), Cs1 = [A|Cs], Cs1 = Cs), list_list_intersection(As,Bs,Cs).

?- list_list_intersection([1,3,5,2,4],[6,1,2],Intersection).
Intersection = [1, 2].                    % succeeds deterministically

以下是您在问题中发布的查询:

?- A=1,B=3, list_list_intersection([1,3,5,2,4],[A,B],Intersection).
A = 1,
B = 3,
Intersection = [1, 3].
?- list_list_intersection([1,3,5,2,4],[A,B],Intersection),A=1,B=3.
A = 1,
B = 3,
Intersection = [1, 3] ;
false.

让我们尝试别的......以下两个查询在逻辑上应该是等价的:

list_list_union(As,Bs,Cs)

而且......底线是?

  • 使用纯粹的代码,很容易保持逻辑健全的一面
  • 不纯的代码,另一方面,通常不会像#34那样;它做了它应该做的事情"乍一看,但显示各种不合逻辑的行为与上面显示的查询。

编辑2015-04-23

list_list_intersection(As,Bs,Cs)Cs都不保证As不包含重复项。如果这让您感到困扰,则需要对代码进行调整。

以下是包含重复项的Bs和/或?- list_list_intersection([1,3,5,7,1,3,5,7],[1,2,3,1,2,3],Cs). Cs = [1, 3, 1, 3]. ?- list_list_intersection([1,2,3],[1,1,1,1],Cs). Cs = [1]. ?- list_list_union([1,3,5,1,3,5],[1,2,3,1,2,3],Cs). Cs = [1, 3, 5, 1, 3, 5, 2, 2]. ?- list_list_union([1,2,3],[1,1,1,1],Cs). Cs = [1, 2, 3]. ?- list_list_union([1,1,1,1],[1,2,3],Cs). Cs = [1, 1, 1, 1, 2, 3]. 的更多查询(和答案):

list_list_intersectionSet([],_,[]).
list_list_intersectionSet([A|As1],Bs,Cs1) :-
    if_(list_item_isMember(Bs,A), Cs1 = [A|Cs], Cs1 = Cs),
    list_item_subtracted(As1,A,As),
    list_list_intersectionSet(As,Bs,Cs).

list_list_unionSet([],Bs1,Bs) :-
    list_setB(Bs1,Bs).
list_list_unionSet([A|As1],Bs1,[A|Cs]) :-
    list_item_subtracted(As1,A,As),
    list_item_subtracted(Bs1,A,Bs),
    list_list_unionSet(As,Bs,Cs).

编辑2015-04-24

为了完整起见,我们可以通过以下方式强制执行交集和联合 - 即不包含任何重复元素的列表。

以下代码非常简单:

list_list_unionSet/3

请注意,list_setB/2基于list_list_intersectionSet/3,定义为previous answer

现在让我们看一下list_list_unionSet/3?- list_list_unionSet([1,2,3,1,2,3,3,2,1],[4,5,6,2,7,7,7],Xs). Xs = [1, 2, 3, 4, 5, 6, 7]. ?- list_list_intersectionSet([1,2,3,1,2,3,3,2,1],[4,5,6,2,7,7,7],Xs). Xs = [2]. 的实际操作:

list_item_subtracted/3

编辑2019-01-30

以下是来自@ GuyCoder的评论(以及它的两个变体)的附加查询:

?- list_list_unionSet(Xs,[],[a,b]).
   Xs = [a,b]
;  Xs = [a,b,b]
;  Xs = [a,b,b,b]
...

?- list_list_unionSet([],Xs,[a,b]).
   Xs = [a,b]
;  Xs = [a,b,b]
;  Xs = [a,b,b,b]
...

?- list_list_unionSet(Xs,Ys,[a,b]).
   Xs = [], Ys = [a,b]
;  Xs = [], Ys = [a,b,b]
;  Xs = [], Ys = [a,b,b,b]
...

使用旧版本的trains = np.arange(1, 101) #The above are example values, it's actually 900 integers between 1 and 20000 tresholds = np.arange(10, 70, 10) tuples = [] for i in trains: for j in tresholds: tuples.append((i, j)) index = pd.MultiIndex.from_tuples(tuples, names=['trains', 'tresholds']) df = pd.DataFrame(np.zeros((len(index), len(trains))), index=index, columns=trains, dtype=float) metrics = dict() for i in trains: m = binary_metric_train(True, i) #Above function returns a binary array of length 35 #Example: [1, 0, 0, 1, ...] metrics[i] = m for i in trains: for j in tresholds: trA = binary_metric_train(True, i, tresh=j) for k in trains: if k != i: trB = metrics[k] corr = abs(pearsonr(trA, trB)[0]) df[k][i][j] = corr else: df[k][i][j] = np.nan ,上述查询并未以存在方式终止。

他们做了新的。 由于解决方案集大小是无限的,因此这些查询都不会普遍终止。

答案 2 :(得分:2)

要比我的第一个答案略微欺骗,你可以使用 findall 更高阶谓词,让Prolog为你做递归:

4 ?- L1=[1,3,5,2,4], L2=[6,1,2], findall(X, (nth0(N, L1, X), member(X, L2)), Res).
L1 = [1, 3, 5, 2, 4],
L2 = [6, 1, 2],
Res = [1, 2].

答案 3 :(得分:1)

如果目标只是“完成工作”,那么swi prolog就已经为此目的建立了原语:

[trace] 3 ?- intersection([1,3,5,2,4] ,[6,1,2], X).
intersection([1,3,5,2,4] ,[6,1,2], X).
X = [1, 2].

[trace] 4 ?- union([1,3,5,2,4] ,[6,1,2], X).
X = [3, 5, 4, 6, 1, 2].

答案 4 :(得分:0)

试试这个,类似于 union/3 here

:- use_module(library(clpfd)).

member(_, [], 0).
member(X, [Y|Z], B) :-
   (X #= Y) #\/ C #<==> B,
   member(X, Z, C).

intersect([], _, []).
intersect([X|Y], Z, T) :-
   freeze(B, (B==1 -> T=[X|R]; T=R)),
   member(X, Z, B),
   intersect(Y, Z, R).

如果元素是整数则有效,并且不留下任何选择点:

?- intersect([X,Y],[Y,Z],L).
freeze(_15070,  (_15070==1->L=[X, Y];L=[Y])),
_15070 in 0..1,
_15166#\/_15168#<==>_15070,
_15166 in 0..1,
X#=Y#<==>_15166,
X#=Z#<==>_15168,
Y#=Z#<==>_15258,
_15168 in 0..1,
_15258 in 0..1.

?- intersect([X,Y],[Y,Z],L), X=1, Y=2, Z=3.
X = 1,
Y = 2,
Z = 3,
L = [2].

?- intersect([X,Y],[Y,Z],L), X=3, Y=2, Z=3.
X = Z, Z = 3,
Y = 2,
L = [3, 2].

答案 5 :(得分:-1)

最后(真的),你可以使用findall找到所有解决方案,然后使用nth0来提取第一个解决方案,这将为你提供你想要的结果而不需要削减,并保持谓词的美观和干净,没有任何额外的谓词来阻止/停止prolog做它最擅长的事情 - 回溯并找到多个答案。

编辑:可以说,在“核心逻辑”中加入额外的谓词以防止生成多个结果,与使用您试图避免的削减一样丑陋/混乱。但也许这是一个学术练习来证明它可以在不使用像findall或内置交集/联合的高阶谓词的情况下完成。

inter([], _, []).

inter([H1|T1], L2, [H1|Res]) :-
    member(H1, L2),
    inter(T1, L2, Res).

inter([_|T1], L2, Res) :-
    inter(T1, L2, Res).

test(First):-
        findall(Ans, inter([1,3,5,2,4], [6,1,2], Ans), Ansl), 
        nth0(0, Ansl, First).

答案 6 :(得分:-2)

我知道这篇文章很老,但我找到了一个编码最少的解决方案。

% intersection
intersection([],L1,L2,L3).
intersection([H|T],L2,L3,[H|L4]):-member(H,L2),intersection(T,L3,L3,L4).
% member
member(H,[H|T]).
member(X,[H|T]):-member(X,T).

要测试上述代码,您不应输入L3。这是一个例子。

?- intersection([w,4,g,0,v,45,6],[x,45,d,w,30,0],L).
L = [w, 0, 45].

答案 7 :(得分:-2)

%元素X在列表中?

pert(X,[X | _])。

pert(X,[_ | L]): - pert(X,L)。

两个列表的联盟

union([],L,L)。

union([X | L1],L2,[X | L3]): - \ + pert(X,L2),union(L1,L2,L3)。

union([_ | L1],L2,L3): - union(L1,L2,L3)。

%两个列表的交点

inter([],_,[])。

inter([X | L1],L2,[X | L3]): - pert(X,L2),inter(L1,L2,L3)。

inter([_ | L1],L2,L3): - inter(L1,L2,L3)。