List Prolog中的子集
我正在寻找这样一个谓词:List Prolog中的子集,list,prolog,set,subset,List,Prolog,Set,Subset,我正在寻找这样一个谓词: ?- subset([1,2,3], X). X = [] ; X = [1] ; X = [2] ; X = [3] ; X = [1, 2] ; X = [1, 2, 3] ; X = [2, 3] ; ... 我见过一些subset实现,但当您想要检查一个列表是否是另一个列表的子集时,它们都可以工作,而不是当您想要生成子集时。有什么想法吗?关于,您将发现一个名为subseq0的谓词的实现,它实现了您想要的功能: subseq0(List, List). subs
?- subset([1,2,3], X).
X = [] ;
X = [1] ;
X = [2] ;
X = [3] ;
X = [1, 2] ;
X = [1, 2, 3] ;
X = [2, 3] ;
...
我见过一些subset
实现,但当您想要检查一个列表是否是另一个列表的子集时,它们都可以工作,而不是当您想要生成子集时。有什么想法吗?关于,您将发现一个名为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的子集子序列,而subseq1(X,Y)
检查Y是否是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.
下面是一个实现:
subset([], []).
subset([E|Tail], [E|NTail]):-
subset(Tail, NTail).
subset([_|Tail], NTail):-
subset(Tail, NTail).
它将生成所有子集,尽管不是按照示例中显示的顺序
根据评论员的要求,这里有一个解释:
第一个子句是基本情况。它表示空列表是空列表的子集
第二和第三个子句处理递归。第二个子句说明,如果两个列表具有相同的头部,并且右列表的尾部是左列表尾部的子集,则右列表是左列表的子集
第三个子句说明,如果我们跳过左列表的头部,而右列表是左列表尾部的子集,那么右列表就是左列表的子集
上面显示的过程生成有序集。对于无序集,您可以使用排列/3
:
unordered_subset(Set, SubSet):-
length(Set, LSet),
between(0,LSet, LSubSet),
length(NSubSet, LSubSet),
permutation(SubSet, NSubSet),
subset(Set, NSubSet).
集合是定义为不同对象的集合。子集过程不应该关心集合中元素的顺序(在参数中)。合适的解决方案(swi prolog)可能如下所示:
subset(_, []).
subset([X|L], [A|NTail]):-
member(A,[X|L]),
subset(L, NTail),
not(member(A, NTail)).
对于问题?-子集([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.
希望这会有帮助 我们还可以通过从超集中删除子集的项来进行测试
% 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]
这将生成子序列,而不是子集。不过,在处理唯一元素的排序列表时也是如此。你基本上是对的(更正了)。但是为什么您需要对列表进行排序呢?您是对的,当列表没有排序时,它也会工作,只是
uniq
'd。但是获得唯一元素的最简单方法是通过sort/2
:)您能解释一下第三条规则吗?我不太明白它的用途。这只适用于排序集,我接受了吗<代码>子集([2,1],[1,2,3])。说不。@JordanScales:您的示例是切换参数,它应该读取子集([1,2,3],[2,1])
,当过程生成有序子集时,它确实会回答false。您可以使用unordered_subset/3
(添加到答案中)@gusbro这是我第一次开始学习Prolog时写的代码。出于某种奇怪的原因,它不适用于SWI Prolog 7.2.3。在回溯过程中,SWI Prolog在重做第二个子句的过程中反复追加一个未绑定的变量作为尾部变量,回溯永远不会结束。您应该切换子集(X,Y)谓词中的参数,以便我们自然地读取X是Y的子集,而不是像您那样:Y是X的子集。子集([a,B],[C,D])。
失败。它应该成功。@false[C,D]不是它应该是[a,B]的子集fail@BaoThai:它当然是一个子集(答案替换为a=C,B=D;a=D,B=C
)@BaoThai:Whilesubset([a],[B])
成功地替换了a=B
,上面失败了。@BaoThai:偶数子集([a,B],[a,B])。
失败了,我们至少可以同意这是错误的吗?此解决方案返回[a,b]
和[b,a]
,而事实上,元素的顺序并不相关,只应将其中一个元素列为子集,因为它们代表同一集合。
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