我正在尝试编写一个将列表分为N个部分的谓词。 这就是我到目前为止所拥有的。
partition(1, List, List).
partition(N, List, [X,Y|Rest]):-
chop(List, X, Y),
member(NextToChop, [X,Y]), %Choose one of the new parts to chop further.
NewN is N-1,
partition(NewN, NextToChop, Rest).
chop(List, _, _):-
length(List, Length),
Length < 2, %You can't chop something that doesn't have at least 2 elements
fail,!.
chop(List, Deel1, Deel2):-
append(Deel1, Deel2, List),
Deel1 \= [],
Deel2 \= [].
我的想法是将列表中的部分切成另外两个部分,直到我有N个部分。 我用这种方法得到了平庸的结果:
?- partition(2, [1,2,3,4], List).
List = [[1], [2, 3, 4], 1] ;
List = [[1], [2, 3, 4], 2, 3, 4] ;
List = [[1, 2], [3, 4], 1, 2] ;
List = [[1, 2], [3, 4], 3, 4] ;
List = [[1, 2, 3], [4], 1, 2, 3] ;
List = [[1, 2, 3], [4], 4] ;
false.
所以我得到了我想要的东西,但是我得到了两次并且还有其他一些东西。 分成3部分时情况会变得更糟:
?- partition(3, [1,2,3,4], List).
List = [[1], [2, 3, 4], [2], [3, 4], 2] ;
List = [[1], [2, 3, 4], [2], [3, 4], 3, 4] ;
List = [[1], [2, 3, 4], [2, 3], [4], 2, 3] ;
List = [[1], [2, 3, 4], [2, 3], [4], 4] ;
List = [[1, 2], [3, 4], [1], [2], 1] ;
List = [[1, 2], [3, 4], [1], [2], 2] ;
List = [[1, 2], [3, 4], [3], [4], 3] ;
List = [[1, 2], [3, 4], [3], [4], 4] ;
List = [[1, 2, 3], [4], [1], [2, 3], 1] ;
List = [[1, 2, 3], [4], [1], [2, 3], 2, 3] ;
List = [[1, 2, 3], [4], [1, 2], [3], 1, 2] ;
List = [[1, 2, 3], [4], [1, 2], [3], 3] ;
false.
另一个想法是使用前缀,但我不知道这将如何工作。要使用它,我应该能够让Prolog知道它需要一个不太短而且不太长的前缀,所以我不会采用太长的前缀,所以没有任何东西可以用于下一个递归步骤。
有人能指出我正确的方向吗?
很少澄清:谓词应该返回在N个部分(不包括空列表)中划分列表的所有可能性。
答案 0 :(得分:5)
在描述涉及列表的关系时,DCG通常非常有用。考虑:
list_n_parts(List, N, Parts) :-
length(Parts, N),
phrase(parts(Parts), List).
parts([]) --> [].
parts([Part|Parts]) --> part(Part), parts(Parts).
part([P|Ps]) --> [P], list(Ps).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
示例查询:
?- list_n_parts([1,2,3,4], 2, Ps).
Ps = [[1], [2, 3, 4]] ;
Ps = [[1, 2], [3, 4]] ;
Ps = [[1, 2, 3], [4]] ;
false.
答案 1 :(得分:3)
以下是我用来实现该方法的基本方法(使用append/2
和length/2
):
list_n_parts(List, Parts, Result) :-
length(Result, Parts),
append(Result, List).
现在,这并不完全符合您的期望:它允许[]
。
要解决此问题的一个想法是使用maplist
调用事先格式化结果列表:
list_n_parts(List, Parts, Result) :-
length(Result, Parts),
使用copy_term/2
,maplist/2
调用如下:
maplist(copy_term([_|_]), Result),
使用functor/3
(信用@false),它看起来像:
maplist(functor('.', 2), Result),
使用lambda.pl你可以写:
maplist(\[_|_]^true, Result),
因为'\'已经执行了术语副本(感谢@false)。
唯一剩下的就是append/2
电话:
append(Result, List).
另一个想法是使用forall/2
过滤(可能更容易获得,但复杂性更差):
list_n_parts(List, Parts, Result) :-
length(Result, Parts),
append(Result, List),
forall(member(X, Result), X \= []).
等...