我正在尝试制作一个代码,按顺序生成集合的所有子集。
也就是说,调用subset([1,2,3], X)
应该生成
X = [];
X = [1];
X = [2];
X = [3];
X = [1,2];
X = [1,3];
X = [2,3];
X = [1,2,3].
内部顺序并不是那么重要,只是首先列出最小的子集(即我不关心[2,3]是否在[1,2]之前,只有1, [2]和[3]在[2,3]之前。
-
到目前为止,我尝试了两种方法。首先,我自己尝试制作谓词......
subset([], []).
subset(List, []).
subset(List, [N]) :-
member(N, List).
subset(List, [N|Rest]) :-
!,
nth0(I, List, N),
findall(E, (nth0(J, List, E), J > I), NewList),
subset2(NewList, Rest).
......但它甚至没有达到预期的效果。其次,我尝试制作powerset(使用this subset predicate)并使用list_to_ord_set / 2进行排序,但我无法使其工作。
帮助?
答案 0 :(得分:3)
在描述列表时,请始终考虑使用DCG notation。
例如:
list_sublist(Ls0, Ls) :-
same_length(Ls0, Ls1),
append(Ls, _, Ls1),
phrase(sublist(Ls0), Ls).
sublist([]) --> [].
sublist([L|Ls]) --> ( [] ; [L] ), sublist(Ls).
示例查询:
?- list_sublist([a,b,c], Ls).
Ls = [] ;
Ls = [c] ;
Ls = [b] ;
Ls = [a] ;
Ls = [b, c] ;
Ls = [a, c] ;
Ls = [a, b] ;
Ls = [a, b, c] ;
false.
另一个例子:
?- list_sublist(Ls, [b,c]).
Ls = [b, c] ;
Ls = [_G511, b, c] ;
Ls = [b, _G514, c] ;
Ls = [b, c, _G517] ;
etc.
最常见的情况:
?- list_sublist(Xs, Ys).
Xs = Ys, Ys = [] ;
Xs = [_G513],
Ys = [] ;
Xs = Ys, Ys = [_G513]
Xs = [_G513, _G516],
Ys = [] ;
etc.
答案 1 :(得分:1)
我发现了一个不那么优雅的解决方案......它需要剪切和一些内置
subset(Xs, Ys) :-
length(Xs, L),
between(0, L, N),
length(Ys, N),
assign(Xs, Ys).
assign(_, []) :- !.
assign([X|Xs], [X|Ys]) :-
assign(Xs, Ys).
assign([_|Xs], Ys) :-
assign(Xs, Ys).
正如@Fatalize所指出的,我们可以避免削减,只是在1 ^子句的第一个参数上强制空列表:
assign([], []).
assign([X|Xs], [X|Ys]) :-
assign(Xs, Ys).
assign([_|Xs], Ys) :-
assign(Xs, Ys).
我避免交换2 ^和3 ^子句,因此'自然'顺序仍然保存得很好