以下是根据我的previous answer转Remove duplicates in list (Prolog);
其基本思想依次是基于@false's answer 到Prolog union for A U B U C。
我想向你传达什么信息?
- 您可以用逻辑纯度在 Prolog 中描述您想要的内容。
- 使用
if_/3 和(=)/3 可以实现逻辑纯
-
都高效(仅在需要时留下选择点)
-
和单调(在泛化/专业化方面合乎逻辑)。
- @false 的谓词
if_/3 和 (=)/3 的实现确实在内部使用元逻辑 Prolog 功能,但(从外部)在逻辑上表现纯粹。
list_list_intersection/3 和list_list_union/3 的以下实现使用list_item_isMember/3 和list_item_subtracted/3,在previous answer 中定义:
list_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.
而且...底线是?
- 使用纯代码很容易保持逻辑合理性。
- 另一方面,不纯代码往往乍一看就像“它做了它应该做的”,但通过上面显示的查询显示出各种不合逻辑的行为。
编辑 2015-04-23
list_list_union(As,Bs,Cs) 和 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].
编辑 2015-04-24
为了完整起见,下面是我们如何强制交集和并集是集合——即不包含任何重复元素的列表。
以下代码非常简单:
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).
请注意,list_list_unionSet/3 基于list_setB/2,定义为here。
现在让我们看看list_list_intersectionSet/3 和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].
编辑 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]
...
对于旧版本的list_item_subtracted/3,上述查询不会存在终止。
他们用新的。
由于解决方案集大小是无限的,因此这些查询都不会普遍终止。