一种使用“开放列表”来附加在遍历列表列表时遇到的元素的解决方案,列表本质上是一棵树,以前缀方式。
指示的示例表明深度为 0 的非列表元素应被丢弃,其他元素按深度排序。但是,没有给出确切的规格。
确实,人们会期待扁平化的结果
[[[[a]],b,[c]],d,e,[f]]
成为
[b,f,c,a]
通过深度值对的“按深度排序”对列表:
[3-a,1-b,2-c,1-f]
但是问题发布者要求这个结果:
[f, a, b, c]
我真的不知道这是否是一个错误。
:- debug(flatwalker).
flatwalker(ListIn,ListOut) :-
Tip=Fin, % 2 unbound variables
% % designating the same memory
% % cell. Hold the Tip, grow at Fin.
flatwalker_2(0,ListIn,Fin,TerFin), % Elements are appended at Fin.
% % The final Fin is found in TerFin
% % on success.
TerFin=[], % Unify TerFin with [], closing
% % the list at Tip.
keysort(Tip,Sorted), % Sort the closed list at Tip
% % by pair key, i.e. by depth.
% % keysort/2 is stable and keeps
% % duplicates.
debug(flatwalker,"Got : ~q",[Tip]),
maplist([_-V,V]>>true,Sorted,ListOut). % Remove depth values.
% ---
% flatwalker_2(+Depth,+TreeIn,+Fin,+TerFin)
% Depth: Input integer, indicates current tree depth.
% TreeIn: The list to flatten at this depth (it's a node of the tree,
% which may or may not contain subtrees, i.e. lists)
% Fin: Always an unbound variable denoting the end of an open list to
% which we will append.
% ("points to an empty memory cell at the fin of the open list")
% Works as an accumulator as a new Fin, advanced by 1 cell at each
% append operation is handed to the next flatwalker_2/4
% activation.
% TerFin: When flatwalker_2/ is done, the final Fin is unified with
% TerFin so that it can be passed to flatwalker/2.
% ---
% We make the guards explicit and cut heavily.
% Optimizing the guards (if so desired) is left as an exercise.
flatwalker_2(_,[],Fin,Fin) :- !. % Done as TreeIn is empty.
% Unify Fin with TerFin.
flatwalker_2(0,[X|Xs],Fin,TerFin) :- % Case of X is nonlist at depth 0:
% % discard!
\+is_list(X),!,
flatwalker_2(0,Xs,Fin,TerFin). % Continue with the rest of the
% list at this depth.
flatwalker_2(D,[X|Xs],Fin,TerFin) :- % Case of X is nonlist at
% % depth > 0: keep!
D>0,\+is_list(X),!,
Fin=[D-X|Fin2], % Grow the result list at its
% % Fin by D-X.
flatwalker_2(D,Xs,Fin2,TerFin). % Continue with the rest of the
% list at this depth.
flatwalker_2(D,[X|Xs],Fin,TerFin) :- % Case of X is a list at any
% % depth.
is_list(X),!,
DD is D+1,
flatwalker_2(DD,X,Fin,Fin2), % Collect one level down
flatwalker_2(D,Xs,Fin2,TerFin). % On return, continue with the
% rest of the list at this depth.
一些plunit 测试:
:- begin_tests(flatwalker).
test("empty",true(Out == [])) :-
flatwalker([],Out).
test("simple",true(Out == [])) :-
flatwalker([1,2,3],Out).
test("with empties",true(Out == [])) :-
flatwalker([[],1,[],2,[],3,[]],Out).
test("test 1",true(Out == [a, b, c, d, e])) :-
flatwalker([1,2,[a,b,c],3,4,[d,e]],Out).
test("test 2",true(Out == [a, b])) :-
flatwalker([1,[],2,3,4,[a,b]],Out).
test("test 3",true(Out == [f, a])) :-
flatwalker([[[[a]]],b,c,d,e,[f]],Out).
test("test 4",true(Out == [f, a, b, c])) :-
flatwalker([[[[a]],b,[c]],d,e,[f]],Out).
:- end_tests(flatwalker).
所以:
?- run_tests.
% PL-Unit: flatwalker
% Got : []
.
% Got : []
.
% Got : []
.
% Got : [1-a,1-b,1-c,1-d,1-e]
.
% Got : [1-a,1-b]
.
% Got : [3-a,1-f]
.
% Got : [3-a,1-b,2-c,1-f]
ERROR: flatwalker.pl:66:
test test 4: wrong answer (compared using ==)
ERROR: Expected: [f,a,b,c]
ERROR: Got: [b,f,c,a]
done
% 1 test failed
% 6 tests passed
false.