一个序言谓词,用于将列表拆分为单独的列表,每 n 个元素
A prolog predicate to split a list into sperate lists ever n elements
标题是必需的谓词,这里有几个示例查询
?- splitEvery(2,[a,b,c,d,e,f,g,h],R).
R = [[a, b], [c, d], [e, f], [g, h]] ;
false.
?- splitEvery(4,[a,b,c,d,e,f,g,h],R).
R = [[a, b, c, d], [e, f, g, h]] ;
false.
?- splitEvery(8,[a,b,c,d,e,f,g,h],R).
R = [[a, b, c, d, e, f, g, h]] ;
false.
到目前为止我的代码是这样的
splitEvery(N,List,Res):-
splitEveryHelper1(N,List,Res,1,[]).
splitEveryHelper1(_,[],Acc,_,Acc).
splitEveryHelper1(N,[H|T],Res,C,[[H|HT]|AT]):-
C=<N,
C\_new is C+1,
splitEveryHelper1(N,T,Res,C_new,[[HT]|AT]).
splitEveryHelper1(N,List,Res,C,[AH|TR]):-
C>N,
C\_new=1,
splitEveryHelper1(N,List,Res,C_new,AT).
但是它不能正常工作
此压缩片段满足您列出的查询
splitEvery(N,L,R) :-
length(R,_),
maplist({N}/[X]>>length(X,N),R),
append(R,L).
但它有一个很大的缺陷(除了需要库(yall))。你能发现吗?
编辑
关于你的代码:你做的比要求的更复杂,并且忽略了编译器给你的关于单例的消息。
请记住,累加器会反转列表,因此您应该删除它们。在输出参数中构建列表。
给你一个开始:
splitEvery(N,List,Res):-
splitEveryHelper1(N,List,1,Res).
splitEveryHelper1(_,[],_,[]).
splitEveryHelper1(N,[H|T],C,[[H|R]|AT]):-
C=<N,
C_new is C+1,
....
splitEveryHelper1(N,List,C,[[]|TR]):-
C>N,
C_new=1,
....
用适当的递归调用填满圆点。然后它会正常工作。
有助于分解你的问题。您想获取事物列表并将其拆分为 N 项的单独子列表,对吗?
这是重复执行以下操作的问题:
- 从列表头部拉出不超过 N 项,并且
- 对剩下的内容进行递归。
因此,您需要一个谓词来从列表的前面提取不超过 N 项。有 3 种情况:
一般情况:N > 0 且列表非空。在这里,我们将列表的头部添加到我们正在构建的前缀中,递减 N,然后递归剩下的内容。
特例 #1:N > 0 且列表为空。在这里,我们关闭前缀和 return 空列表作为后缀。
特殊情况 #2:N 为 0。这里,我们关闭前缀和 return 源列表作为后缀。
first( N , [X|L] , [X|Xs] , Sfx ) :- N > 0 , N1 is N-1 , first( N1, L, Xs, Sfx ) .
first( N , [] , [] , [] ) :- N > 0 .
first( 0 , Xs , [] , Xs ) .
一旦我们有了它,重复调用 first/4
.
就更容易了
- 如果源列表为空,则列表列表为空。
- 如果源列表非空,我们
- 从源列表中拉出前 N 项,然后
- 对剩下的东西进行递归
split_every( _ , [] , [] ) .
split_every( N , [X|Xs] , [Pfx|LoL] ) :- first(N,[X|Xs],Pfx,Sfx), split_every(N,Sfx,LoL) .
你可以,呃……fiddle 在这个 fiddle: https://swish.swi-prolog.org/p/split-list.pl
标题是必需的谓词,这里有几个示例查询
?- splitEvery(2,[a,b,c,d,e,f,g,h],R).
R = [[a, b], [c, d], [e, f], [g, h]] ;
false.
?- splitEvery(4,[a,b,c,d,e,f,g,h],R).
R = [[a, b, c, d], [e, f, g, h]] ;
false.
?- splitEvery(8,[a,b,c,d,e,f,g,h],R).
R = [[a, b, c, d, e, f, g, h]] ;
false.
到目前为止我的代码是这样的
splitEvery(N,List,Res):-
splitEveryHelper1(N,List,Res,1,[]).
splitEveryHelper1(_,[],Acc,_,Acc).
splitEveryHelper1(N,[H|T],Res,C,[[H|HT]|AT]):-
C=<N,
C\_new is C+1,
splitEveryHelper1(N,T,Res,C_new,[[HT]|AT]).
splitEveryHelper1(N,List,Res,C,[AH|TR]):-
C>N,
C\_new=1,
splitEveryHelper1(N,List,Res,C_new,AT).
但是它不能正常工作
此压缩片段满足您列出的查询
splitEvery(N,L,R) :-
length(R,_),
maplist({N}/[X]>>length(X,N),R),
append(R,L).
但它有一个很大的缺陷(除了需要库(yall))。你能发现吗?
编辑
关于你的代码:你做的比要求的更复杂,并且忽略了编译器给你的关于单例的消息。
请记住,累加器会反转列表,因此您应该删除它们。在输出参数中构建列表。
给你一个开始:
splitEvery(N,List,Res):-
splitEveryHelper1(N,List,1,Res).
splitEveryHelper1(_,[],_,[]).
splitEveryHelper1(N,[H|T],C,[[H|R]|AT]):-
C=<N,
C_new is C+1,
....
splitEveryHelper1(N,List,C,[[]|TR]):-
C>N,
C_new=1,
....
用适当的递归调用填满圆点。然后它会正常工作。
有助于分解你的问题。您想获取事物列表并将其拆分为 N 项的单独子列表,对吗?
这是重复执行以下操作的问题:
- 从列表头部拉出不超过 N 项,并且
- 对剩下的内容进行递归。
因此,您需要一个谓词来从列表的前面提取不超过 N 项。有 3 种情况:
一般情况:N > 0 且列表非空。在这里,我们将列表的头部添加到我们正在构建的前缀中,递减 N,然后递归剩下的内容。
特例 #1:N > 0 且列表为空。在这里,我们关闭前缀和 return 空列表作为后缀。
特殊情况 #2:N 为 0。这里,我们关闭前缀和 return 源列表作为后缀。
first( N , [X|L] , [X|Xs] , Sfx ) :- N > 0 , N1 is N-1 , first( N1, L, Xs, Sfx ) .
first( N , [] , [] , [] ) :- N > 0 .
first( 0 , Xs , [] , Xs ) .
一旦我们有了它,重复调用 first/4
.
- 如果源列表为空,则列表列表为空。
- 如果源列表非空,我们
- 从源列表中拉出前 N 项,然后
- 对剩下的东西进行递归
split_every( _ , [] , [] ) .
split_every( N , [X|Xs] , [Pfx|LoL] ) :- first(N,[X|Xs],Pfx,Sfx), split_every(N,Sfx,LoL) .
你可以,呃……fiddle 在这个 fiddle: https://swish.swi-prolog.org/p/split-list.pl