将列表分成具有特定大小的子列表
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 ;
我需要以这种方式划分列表:第一个和最后一个子列表包含 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 ;