如何生成列表元素的所有可能组合?
例如,根据列表[1,2,3]
,我想设计一个格式为comb([1,2,3], L).
的谓词,该谓词应返回L
的以下答案:
[1]
[2]
[3]
[1,2]
[2,1]
[1,3]
[3,1]
[2,3]
[3,2]
[1,2,3]
[1,3,2]
[2,1,3]
[2,3,1]
[3,1,2]
[3,2,1]
答案 0 :(得分:10)
您要求的内容涉及列表的组合(选择子集)和排列(重新排列顺序)。
您的示例输出意味着空列表不被视为有效解决方案,因此我们将在后面的实现中将其排除。如果这是一个疏忽,重新考虑。此实现也会以与示例输出不同的顺序生成解决方案。
comb(InList,Out) :-
splitSet(InList,_,SubList),
SubList = [_|_], /* disallow empty list */
permute(SubList,Out).
splitSet([ ],[ ],[ ]).
splitSet([H|T],[H|L],R) :-
splitSet(T,L,R).
splitSet([H|T],L,[H|R]) :-
splitSet(T,L,R).
permute([ ],[ ]) :- !.
permute(L,[X|R]) :-
omit(X,L,M),
permute(M,R).
omit(H,[H|T],T).
omit(X,[H|L],[H|R]) :-
omit(X,L,R).
用Amzi测试过!序言:
?- comb([1,2,3],L).
L = [3] ;
L = [2] ;
L = [2, 3] ;
L = [3, 2] ;
L = [1] ;
L = [1, 3] ;
L = [3, 1] ;
L = [1, 2] ;
L = [2, 1] ;
L = [1, 2, 3] ;
L = [1, 3, 2] ;
L = [2, 1, 3] ;
L = [2, 3, 1] ;
L = [3, 1, 2] ;
L = [3, 2, 1] ;
no
答案 1 :(得分:4)
通过根据same_length/2
,prefix/2
,foldl/4
定义comb/2
来保持纯洁,
select/3
:
comb(As,Bs) :- same_length(As,Full), Bs = [_|_], prefix(Bs,Full), foldl(select,Bs,As,_).
以下是OP给出的示例查询:
?- comb([1,2,3],Xs).
Xs = [1]
; Xs = [2]
; Xs = [3]
; Xs = [1,2]
; Xs = [1,3]
; Xs = [2,1]
; Xs = [2,3]
; Xs = [3,1]
; Xs = [3,2]
; Xs = [1,2,3]
; Xs = [1,3,2]
; Xs = [2,1,3]
; Xs = [2,3,1]
; Xs = [3,1,2]
; Xs = [3,2,1]
; false.
确定!但是如果作为第一个参数给出的列表包含重复项呢?
?- comb([1,1,2],Xs).
Xs = [1]
; Xs = [1] % (redundant)
; Xs = [2]
; Xs = [1,1]
; Xs = [1,2]
; Xs = [1,1] % (redundant)
; Xs = [1,2] % (redundant)
; Xs = [2,1]
; Xs = [2,1] % (redundant)
; Xs = [1,1,2]
; Xs = [1,2,1]
; Xs = [1,1,2] % (redundant)
; Xs = [1,2,1] % (redundant)
; Xs = [2,1,1]
; Xs = [2,1,1] % (redundant)
; false.
不完全!我们可以摆脱上述多余的答案吗?是的,只需使用selectd/3
!
comb(As,Bs) :- same_length(As,Full), Bs = [_|_], prefix(Bs,Full), foldl(selectd,Bs,As,_).
让我们再次使用comb/2
的改进实现重新运行查询!
?- comb([1,1,2],Xs).
Xs = [1]
; Xs = [2]
; Xs = [1,1]
; Xs = [1,2]
; Xs = [2,1]
; Xs = [1,1,2]
; Xs = [1,2,1]
; Xs = [2,1,1]
; false.
答案 2 :(得分:2)
有一个名为permutation的预定义谓词......
1 ?- permutation([1,2,3],L).
L = [1, 2, 3] ;
L = [2, 1, 3] ;
L = [2, 3, 1] ;
L = [1, 3, 2] ;
L = [3, 1, 2] ;
L = [3, 2, 1] .
2 ?- listing(permutation).
lists:permutation([], [], []).
lists:permutation([C|A], D, [_|B]) :-
permutation(A, E, B),
select(C, D, E).
lists:permutation(A, B) :-
permutation(A, B, B).
true.
希望这会有所帮助..
答案 3 :(得分:0)
提示:如果您编写了谓词inselt(X,Y,Z)
,这很容易做到,如果Y
中X
的任何Z
插入inselt([E|X], Y, [E|Z]) :- inselt(X,Y,Z).
inselt(X, Y, [Y|X]).
,则该句词有效:
comb/3
然后可以使用inselt/3
递归编码{{1}}。