【问题标题】:Subsets in PrologProlog 中的子集
【发布时间】:2011-06-22 05:20:40
【问题描述】:

我正在寻找这样的谓词:

?- subset([1,2,3], X).
X = [] ;
X = [1] ;
X = [2] ;
X = [3] ;
X = [1, 2] ;
X = [1, 2, 3] ;
X = [2, 3] ;
...

我见过一些subset 实现,但是当您想要检查一个列表是否是另一个列表的子集时,它们都可以工作,而不是当您想要生成子集时。有什么想法吗?

【问题讨论】:

  • 您应该切换子集(X, Y) 谓词中的参数,以便我们自然地读取 X 是 Y 的子集,而不是像您所做的那样:Y 是 X 的子集。

标签: list prolog set subset


【解决方案1】:

我们也可以通过从超集中删除子集的项目来测试。

% to delete : an item can be deleted it its in the head or in the tail of a list
delete(I,[I|L],L).
delete(I,[H|L],[H|NL]) :- delete(I,L,NL).
% an [] is an item of an set.A set is a subset of we can recursively delete its head item from the super set.
subset(_,[]).
subset(S,[I|SS]) :- delete(I,S,S1), subset(S1,SS).

示例:

subset([a,b,c],S).
S = []
S = [a]
S = [a, b]
S = [a, b, c]
S = [a, c]
S = [a, c, b]
S = [b]
S = [b, a]
S = [b, a, c]
S = [b, c]
S = [b, c, a]
S = [c]
S = [c, a]
S = [c, a, b]
S = [c, b]
S = [c, b, a] 

subset([a,b,a,d,e],[a,e]).
1true

【讨论】:

  • 此解决方案同时返回 [a, b][b, a],实际上,元素的顺序不相关,只有其中一个元素应列为子集,因为它们代表相同的集合.
【解决方案2】:
append([],L,L).

append([H|T],L,[H|L1]):-append(T,L,L1).


subset([X|T],[X|L]) :-subset(T,L).

subset([X|T],[G|L]) :-subset([X],L),append(L2,[X|L3],[G|L]),append(L2,L3,L4),subset(T,L4).

subset([],_).

----------------------------------------------
?- subset([1,2],[1,2]).

yes

?- subset([1,2],[2,1]).

yes

?- subset([1,1],[1,2]).

no

?- subset(D,[1,2]).

D = [1,2] ;

D = [1] ;

D = [2,1] ;

D = [2] ;

D = '[]' ;

no

【讨论】:

    【解决方案3】:

    http://www.probp.com/publib/listut.html 上,您将找到一个名为subseq0 的谓词实现,它可以执行您想要的操作:

    subseq0(List, List).
    subseq0(List, Rest) :-
       subseq1(List, Rest).
    
    subseq1([_|Tail], Rest) :-
       subseq0(Tail, Rest).
    subseq1([Head|Tail], [Head|Rest]) :-
       subseq1(Tail, Rest).
    

    简短说明:subseq0(X, Y) 检查 Y 是否是 X 的 subset 子序列,而 subseq1(X, Y) 检查 Y 是否是 正确 subset s> X 的子序列。

    由于集合的默认表示是具有唯一元素的列表,因此您可以使用它来获取所有子集,如下例所示:

    ?- subseq0([1,2,3], X).
    X = [1, 2, 3] ;
    X = [2, 3] ;
    X = [3] ;
    X = [] ;
    X = [2] ;
    X = [1, 3] ;
    X = [1] ;
    X = [1, 2] ;
    false.
    

    【讨论】:

    • 这会生成子序列,而不是子集。不过,在处理唯一元素的排序列表时也是如此。
    • 您基本上是对的(已更正)。但是为什么需要对列表进行排序呢?
    • 你是对的,当列表未排序时它也可以工作,只是uniq'd。但是获得独特元素的最简单方法是通过sort/2 :)
    【解决方案4】:

    Set 是定义为 distinct 对象的集合。子集过程不应该关心集合中元素的顺序(在参数中)。适当的解决方案(swi prolog)可能如下所示:

    subset(_, []).
    subset([X|L], [A|NTail]):-
        member(A,[X|L]),    
        subset(L, NTail),
        not(member(A, NTail)).
    

    对于问题 ?- subset([1,2,3], E) 它将生成:

    E = [] ;
    E = [1] ;
    E = [1, 2] ;
    E = [1, 2, 3] ;
    E = [1, 3] ;
    E = [2] ;
    E = [2, 3] ;
    E = [3] ;
    E = [3, 2] ;
    false.
    

    希望对您有所帮助!

    【讨论】:

    • subset([A,B],[C,D]). 失败。它应该会成功。
    • @false [C,D] 不是 [A,B] 的子集,它应该会失败
    • @BaoThai:它肯定是一个子集(带有答案替换A = C, B = D ; A = D, B = C
    • @BaoThai:虽然subset([A], [B]) 使用A = B 成功,但上述失败。
    • @BaoThai:即使subset([A,B],[A,B]).失败了,我们至少可以同意这是错误的吗?
    【解决方案5】:

    这是一个实现:

    subset([], []).
    subset([E|Tail], [E|NTail]):-
      subset(Tail, NTail).
    subset([_|Tail], NTail):-
      subset(Tail, NTail).
    

    它将生成所有子集,尽管不是按照示例中显示的顺序。

    根据评论者的要求,这里有一个解释:

    第一个子句是基本情况。它声明空列表是空列表的子集。

    第二个和第三个子句处理递归。第二个子句说明如果两个列表具有相同的 Head 并且右列表的尾部是左列表尾部的子集,则右列表是左列表的子集。

    第三个子句指出,如果我们跳过左链表的头部,而右链表是左链表尾的子集,那么右链表是左链表的子集。

    上面显示的过程生成有序集合。对于无序集,您可以使用 permutation/3:

    unordered_subset(Set, SubSet):-
      length(Set, LSet),
      between(0,LSet, LSubSet),
      length(NSubSet, LSubSet),
      permutation(SubSet, NSubSet),
      subset(Set, NSubSet).
    

    【讨论】:

    • 您能解释一下第三条规则吗?我不太明白它的目的。
    • 这只适用于我接受的排序集? subset([2,1], [1,2,3]). 说不。
    • @JordanScales:您的示例正在切换参数,它应该读取subset([1,2,3],[2,1]),它确实会回答错误,因为该过程会生成有序子集。您可以改用unordered_subset/3(添加到答案中)。
    • @gusbro 这与我刚开始学习 Prolog 时编写的代码相同。由于某些奇怪的原因,它不适用于 SWI-Prolog 7.2.3。在回溯期间,SWI-Prolog 在重做第二个子句期间重复附加一个未绑定的变量,用于 Tail 变量,并且回溯永远不会结束。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多