我正在尝试编写一个程序,它将两个列表作为输入并检查正确的子集。我开始时:
proper([A],[]).
proper([],[A]).
proper([A|T1],[A|T2]) :- proper(T1,T2).
对于输入完全相同的顺序,这非常适用。例如:
?- proper([a,b,c],[a,b,c,d]).
Yes
但不适用于以下输入:
?- proper([a,b,c],[b,d,a,c]).
No
浏览网站后,我发现了之前提出的问题:
这导致我修改我的代码:
proper([A],[]).
proper([],[A]).
proper([A|T1],[A|T2) :- member(A,T2), proper(T1,T2).
proper([H1|T1], [H2|T2]) :- \+ member(H1, T2).
这适用于子集,但不适用于正确的子集。我认为我的问题来自于我对正确/ 4的第二个句子如何工作的理解。非常感谢任何和所有帮助。
编辑:
意识到我试图确定第一个列表是否是第二个的正确子集,而第二个列表是第一个列表的正确子集。清理代码更精确。
proper([],_).
proper([A|T1],[A|T2) :- member(A,T2), proper(T1,T2).
proper([H1|T1], [H2|T2]) :- \+ member(H1, T2).
答案 0 :(得分:2)
如果我理解正确,你上次尝试的前两个声明意味着,两个一个包含1个元素的列表是空列表的正确子集(false),和< / em>空列表是具有一个元素的列表的正确子集(true);第一个应该是有问题的,因为proper([1], [])
和proper([],[1])
一样成功,但正确的子集关系是不对称的。
我认为你的第二次尝试没有过滤掉相同子集的原因是你没有要求A小于B的声明。
以下是我提出的一些可能的解决方案。我使用smaller_set/2
几次以提高清晰度和简洁性。
smaller_set(A, B) :-
length(A, LA),
length(B, LB),
LA < LB.
def_proper_subset/2
尝试捕获子集的标准定义。
def_proper_subset(A, B) :-
smaller_set(A, B), % if A < B then there's some _e in B that isn't in A.
forall(member(_e, A), member(_e, B)).
具有递归定义的示例,基于移除A和B的每个匹配元素。它确保A&lt;如果A在B之前用完了元素,B只会成功。
rec_proper_subset1([], [_|_]).
rec_proper_subset1([_e|A], B) :-
select(_e, B, C), % C is B with _e removed. Only true if _e is in B.
rec_proper_subset1(A, C).
一旦主谓词已经确定A&lt;乙
rec_proper_subset2(A, B) :-
smaller_set(A, B),
rec_proper_subset2_(A, B).
rec_proper_subset2_([], _).
rec_proper_subset2_([_e|A], B) :-
member(_e, B),
rec_proper_subset2_(A, B).
编辑:
list_to_set/2
,sort/2
或类似内容。但是这些解决方案也可以用来查找子列表。def_proper_subset/2
是一种蹩脚的解决方案,因为它只能检查A是B的子集但是不能在A中生成B的子集。另外两个能够想到(我搞砸了,忘了包括rec_proper_subset2/2
的地面定义,但我现在已经修好了。