真子集-Prolog
我正试图编写一个程序,将两个列表作为输入,并检查适当的子集。我从以下几点开始:真子集-Prolog,prolog,subset,Prolog,Subset,我正试图编写一个程序,将两个列表作为输入,并检查适当的子集。我从以下几点开始: 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]) :- 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).
这适用于子集,但不适用于适当的子集。我认为我的问题是因为我理解property/4的第二条是如何工作的。非常感谢您的任何帮助
编辑:
意识到我试图确定第一个列表是否是第二个列表的适当子集,第二个列表是否是第一个列表的适当子集。将代码清理得更精确
proper([],_).
proper([A|T1],[A|T2) :- member(A,T2), proper(T1,T2).
proper([H1|T1], [H2|T2]) :- \+ member(H1, T2).
如果我理解正确,您上次尝试中的前两个声明将意味着,包含1个元素的列表是空列表的适当子集(false),而空列表是包含一个元素的列表的适当子集(true);第一个应该是有问题的,因为
property([1],])
和property([],[1])
都会成功,但是property子集关系是不对称的
我相信您第二次尝试没有过滤出相同子集的原因是您没有要求A小于B的声明
以下是我提出的一些可能的解决方案。为了提高清晰度和简洁性,我使用了两次较小的设置/2
smaller_set(A, B) :-
length(A, LA),
length(B, LB),
LA < LB.
一个递归定义的示例,基于移除A和B的每个匹配元素。它确保A
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
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\u\u-to\u-set/2
,或类似的方法。但这类解决方案也可以用于查找子列表sort/2
- 我认为
是一种蹩脚的解决方案,因为它只能检查a是B的子集,但不能在a中生成B的子集。另外两个可以思考def_property_subset/2
(我搞砸了,忘了包括
rec_property\u subset2/2
的基本定义,但我现在已经修复了它)。只需对列表进行排序即可。这是最明智的做法,也是标准库处理它的方式。@Boris你能告诉我正确子集的标准库谓词吗?@aBathologist看一看库(ordsets)(例如在SWI Prolog实现中)及其源代码。“适当”子集没有谓词,但正如您在回答中所指出的那样,只看长度就足够了。@a语法学家我的观点主要是,当“集合”的概念表示为Prolog列表时,处理它的唯一明智的方法是保持列表的排序。列表是嵌套的术语,只能在一个方向上遍历。@Boris我明白了!这是一个重要的观点。我只是觉得我忽略了一个库,或者有一种特殊的方法可以使用sort来完成正确的子集检查,我无法完全理解。谢谢你的详细阐述。是的,在对它进行了更多的研究之后,我意识到我正在尝试检查A是否是B的适当子集,反之亦然。我对代码进行了编辑,使其更清晰、更精确。@Shrp91供参考:我的部分答案出错,现在已更正错误。我最终使用select/3功能使其正常工作。非常感谢你的回答。
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).