【问题标题】:Proper Subset - Prolog正确的子集 - Prolog
【发布时间】:2013-10-24 05:56:58
【问题描述】:

我正在尝试编写一个程序,该程序将两个列表作为输入并检查适当的子集。我开始了:

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

浏览该网站后,我发现了这个先前提出的问题:

Subset function in prolog

这导致我这样修改我的代码:

proper([A],[]).
proper([],[A]).
proper([A|T1],[A|T2) :- member(A,T2), proper(T1,T2).
proper([H1|T1], [H2|T2]) :- \+ member(H1, T2).

这适用于子集,但不适用于适当的子集。我认为我的问题是由于我对proper/4的第二个子句如何工作的理解而引起的。非常感谢任何和所有帮助。

编辑:

意识到我正在尝试确定第一个列表是否是第二个列表的真子集并且第二个列表是第一个列表的真子集。清理代码以更精确。

proper([],_).
proper([A|T1],[A|T2) :- member(A,T2), proper(T1,T2).
proper([H1|T1], [H2|T2]) :- \+ member(H1, T2).

【问题讨论】:

  • 只需对您的列表进行排序。这是最明智的做法,标准库也是如何处理它的。
  • @Boris 你能告诉我正确子集的标准库谓词吗?
  • @aBathologist 查看 library(ordsets)(例如在 SWI-Prolog 实现中)及其源代码。 “正确”子集没有谓词,但正如您在答案中已经指出的那样,仅查看长度就足够了。
  • @aBathologist 我的观点主要是,当“集合”表示为 Prolog 列表时,处理“集合”概念的唯一明智方法是保持列表排序。列表是嵌套项,只能在一个方向上遍历。
  • @Boris 我明白了!这是一个重要的观点。我只是以为我一直在忽略一个库,或者有一种特殊的方法可以使用 sort 来完成我无法理解的正确子集检查。感谢您的详细说明。

标签: prolog subset


【解决方案1】:

如果我理解正确,您最后一次尝试中的前两个声明将意味着,both 具有 1 个元素的列表是空列表的适当子集(错误),和 空列表是具有一个元素的列表的真子集(真);第一个应该是有问题的,因为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

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_to_set/2sort/2 或类似名称。但这类解决方案也可以用于查找子列表。
  • 我认为def_proper_subset/2是一种蹩脚的解决方案,因为它只能检查A是否是B的子集,但不能在A中生成B的子集。另外两个可以思考。

(我搞砸了,忘记包含rec_proper_subset2/2 的地面定义,但我现在已经修好了)。

【讨论】:

  • 是的,在更多地使用它之后,我意识到我正在尝试检查 A 是否是 B 的适当子集,反之亦然。我编辑了代码,使其更加清晰和精确。
  • @Shrp91 仅供参考:我的部分答案搞砸了,现在已经纠正了错误。
  • 我最终使用了 select/3 函数来让它工作。非常感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多