将列表分成具有特定大小的子列表

Divide list into sublists with specific sizes

我需要以这种方式划分列表:第一个和最后一个子列表包含 1 个元素,第二个和倒数第二个包含 2 个元素,依此类推。我写了一个更简单的谓词版本:我只是把 1 个元素放在第一个子列表,第二个 2 等等。如何编写我需要的谓词?

下面是我的代码:

divide(List, ListOfParts):-
  divide(List, 1, ListOfParts).
  
divide(List, N, [List]):-
  length(List, Len), Len =< N, !.

divide(List, N, [FirstN|TailParts]):-
  append(FirstN, Tail, List),
  length(FirstN, N), !, 
  NextN is N+1,
  divide(Tail, NextN, TailParts).
segment_list(Lst, LstSegments) :-
    length(Lst, LenLst),
    segment_list_(Lst, LenLst, 1, LstSegments).

segment_list_(Lst, LenLst, LenSegment, LstSegments) :-
    % Using compare, to prevent unwanted choicepoint
    compare(Comp, LenLst, 0),
    segment_list_comp_(Comp, Lst, LenLst, LenSegment, LstSegments).

% Have reached end, if "middle" is empty
segment_list_comp_(=, [], 0, _, []).

segment_list_comp_(>, Lst, LenLst, LenSegment, LstSegments) :-
    LenMiddle is LenLst - (LenSegment * 2),
    LenMiddle >= 0,
    % Set length of LstMiddle, to avoid choicepoint in append/2
    length(LstMiddle, LenMiddle),
    % Segment lengths
    length(LstStart, LenSegment),
    length(LstEnd, LenSegment),
    % Segment contents - to make e.g. [1, 3, 4, 2] instead of [1, 2, 3, 4]
    append([LstStart, LstEnd, LstMiddle], Lst),
    LenSegment1 is LenSegment + 1,
    segment_list_(LstMiddle, LenMiddle, LenSegment1, LstSegmentsMiddle),
    % Append after recursion, so LstSegmentsMiddle is nonvar, to prevent infinite loop
    append([[LstStart], LstSegmentsMiddle, [LstEnd]], LstSegments).

(我正在使用 swi-prolog。)

这是确定性的:

?- time(segment_list([a, b, c, d, e, f], LstSeg)).
% 94 inferences, 0.000 CPU in 0.000 seconds (94% CPU, 944088 Lips)
LstSeg = [[a],[c,d],[e,f],[b]].

?- time(segment_list([1, 2, 3, 4, 5, 6], LstSeg)).
% 94 inferences, 0.000 CPU in 0.000 seconds (94% CPU, 932216 Lips)
LstSeg = [[1],[3,4],[5,6],[2]].

...和一般:

?- segment_list(LstRaw, LstSeg), length(LstRaw, LstRawLen).
LstRaw = LstSeg, LstSeg = [],
LstRawLen = 0 ;
LstRaw = [_A,_B],
LstSeg = [[_A],[_B]],
LstRawLen = 2 ;
LstRaw = [_A,_B,_C,_D,_E,_F],
LstSeg = [[_A],[_C,_D],[_E,_F],[_B]],
LstRawLen = 6 ;
LstRaw = [_A,_B,_C,_D,_E,_F,_G,_H,_I,_J,_K,_L],
LstSeg = [[_A],[_C,_D],[_G,_H,_I],[_J,_K,_L],[_E,_F],[_B]],
LstRawLen = 12 ;