简体   繁体   English

一个 prolog 谓词,用于将列表拆分为每 n 个元素的单独列表

[英]A prolog predicate to split a list into sperate lists ever n elements

The title is the required predicate and here are few sample queries标题是必需的谓词,这里有几个示例查询

?- 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.

my code so far is this到目前为止我的代码是这样的

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).

however it is not working properly但是它不能正常工作

This compact fragment satisfies the queries you listed此紧凑片段满足您列出的查询

splitEvery(N,L,R) :-
    length(R,_),
    maplist({N}/[X]>>length(X,N),R),
    append(R,L).

but it has a big flaw (apart requiring library( yall )).但它有一个很大的缺陷(除了需要库( yall ))。 Can you spot it?你能发现吗?

Edit编辑

About your code: you're doing it more complex than required, and ignoring the messages the compiler gives you about singletons.关于你的代码:你做的比要求的更复杂,忽略编译器给你的关于单例的消息。

Remember that accumulators reverse the list, so you should remove them.请记住,累加器会反转列表,因此您应该删除它们。 Build instead the list in the output argument.而是在 output 参数中构建列表。

To give you a start:给你一个开始:

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,
    ....

fill the dots with the proper recursive calls.用适当的递归调用填充点。 Then it will be working properly.然后它将正常工作。

It helps to decompose your problem.它有助于分解您的问题。 You want to take a list of things and split it up into a individual sublists of N items, correct?您想获取一个事物列表并将其拆分为 N 个项目的单个子列表,对吗?

That is a matter of repeatedly doing the following:这是反复执行以下操作的问题:

  • Pulling no more than N items off the head of the list, and从列表的顶部拉出不超过 N 个项目,并且
  • Recursing down on what's left.递归到剩下的东西。

So, you need a predicated to pull no more than N items from the front of the list.因此,您需要一个谓词从列表的前面提取不超过 N 个项目。 There's 3 cases:有3种情况:

  • The general case: N > 0 and the list is non-empty.一般情况:N > 0 且列表非空。 Here, we add the head of the list to the prefix that we're building, decrement N, and recurse down on what's left.在这里,我们将列表的头部添加到我们正在构建的前缀中,递减 N,然后向下递归剩下的内容。

  • Special case #1: N > 0 and the list is empty.特殊情况 #1:N > 0 并且列表为空。 Here, we close the prefix and return the empty list as the suffix.在这里,我们关闭前缀并返回空列表作为后缀。

  • Special case #2: N is 0. Here, We close the prefix and return the source list as the suffix.特殊情况 #2:N 为 0。在这里,我们关闭前缀并将源列表作为后缀返回。

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  ) .

Once we have that, it's an even easier matter of repeatedly invoking first/4 .一旦我们有了它,重复调用first/4就更容易了。

  • If the source list is empty, then the list-of-lists is empty.如果源列表为空,则列表列表为空。
  • If the source list is non-empty, we如果源列表非空,我们
    • pull the first N items from the source list, and从源列表中提取前 N 个项目,并且
    • recurse down on whatever's left over递归到剩下的任何东西
split_every( _ , []     , []        ) .
split_every( N , [X|Xs] , [Pfx|LoL] ) :- first(N,[X|Xs],Pfx,Sfx), split_every(N,Sfx,LoL) .

You can, err... fiddle with it in this fiddle: https://swish.swi-prolog.org/p/split-list.pl你可以,错误......在这个小提琴中摆弄它: https://swish.swi-prolog.org/p/split-list.pl

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM