简体   繁体   English

拼接列表中的子列表,不使用 flatten/2

[英]Splice in sublists in a list, without using flatten/2

I want to make one list of multiple sublists without using the flatten predicate in Prolog.我想在不使用 Prolog 中的flatten谓词的情况下制作一个包含多个子列表的列表。

This is my code:这是我的代码:

acclistsFromList([],A,A).
acclistsFromList([H|T],Listwithinlist,A):-
  not(is_list(H)), 
  acclistsFromList(T,Listwithinlist,A).
acclistsFromList([H|T],Listwithinlist,A):-
  is_list(H), 
  append([H],Listwithinlist,Acc2), 
  acclistsFromList(T,Acc2,A).

I get this as output我得到这个作为输出

?- listsFromList([1,2,[a,b,c],3,4,[d,e]],X). 
X = [[d, e], [a, b, c]] ;

But I want this:但我想要这个:

?- listsFromList([1,2,[a,b,c],3,4,[d,e]],X).
X = [a, b, c, d, e] .

?- listsFromList([1,[],2,3,4,[a,b]],X).
X = [a, b] .

?- listsFromList([[[[a]]],b,c,d,e,[f]],X).
X = [f, a] .

?- listsFromList([[[[a]],b,[c]],d,e,[f]],X).
X = [f, a, b, c] .

What is the best way to reach this result, without using flatten ?在不使用flatten情况下,达到此结果的最佳方法是什么?

The second clause of the acclistsFromList/3 does not do anything with H if it has verified that H is not a list, but you need to prepend the result with H .如果acclistsFromList/3的第二个子句已验证H不是列表,则它不会对H执行任何操作,但您需要在结果前加上H

acclistsFromList([H|T], Listwithinlist, [H|A]) :-
    \+ is_list(H),
    acclistsFromList(T, Listwithinlist, A).

but this is not sufficient.但这还不够。 Since you prepend to the accumulator, the result is reversed.由于您预先添加到累加器,因此结果相反。 You do not need an accumulator here anyway:无论如何,您在这里不需要累加器:

acclistsFromList([], []).
acclistsFromList([H|T], [H|A]) :-
    \+ is_list(H),
    acclistsFromList(T, A).
acclistsFromList([H|T], Result):-
    is_list(H),
    append(H, Res1, Result),
    acclistsFromList(T, Res1).

or without the "scalar" elements:或没有“标量”元素:

acclistsFromList([], []).
acclistsFromList([H|T], A) :-
    \+ is_list(H),
    acclistsFromList(T, A).
acclistsFromList([H|T], Result):-
    is_list(H),
    append(H, Res1, Result),
    acclistsFromList(T, Res1).

This furthermore does not recurse on lists.此外,这不会在列表上递归。 A list of lists of lists will thus not be flattened.因此,列表列表的列表将不会被展平。 I leave it as an exercise to implement this.我把它作为一个练习来实现这个。

This is a one-liner,这是单线,

foo(X,L) :- 
  findall(Z, (member(A,X),is_list(A),member(Z,A)), L).

(as seen here ). (如看到这里)。

To deal with multi-layered nested lists, we need to use a recursive predicate,为了处理多层嵌套列表,我们需要使用递归谓词,

nembr(Z,A) :-    % member in nested lists
  is_list(A), member(B,A), nembr(Z,B)
  ;
  \+ is_list(A), A=Z.

then use it instead of that final member call in findall 's goal:然后使用而不是findall目标中的最终member调用:

bar(X,L) :- 
  findall(Z, (member(A,X),is_list(A),nembr(Z,A)), L).

testing:测试:

10 ?- foo([1,2,[a,b,c],3,4,[d,e]],X).
X = [a, b, c, d, e].

11 ?- bar([1,2,[a,b,c],3,4,[d,e]],X).
X = [a, b, c, d, e].

12 ?- bar([1,2,[a,b,[[[c]]]],3,4,[d,e]],X).
X = [a, b, c, d, e].

In case you want to roll your own, here's breadth-first enumeration of arbitrarily nested lists:如果你想自己滚动,这里是任意嵌套列表的广度优先枚举:

bfs( XS, L) :- bfs( s(z), [XS|Q], Q,  L, []).

bfs( z, _, _, Z, Z).
bfs( s(N), [[]   |P], Q,  L, Z) :- bfs( N, P, Q,  L, Z).
bfs( s(N), [[A|B]|P], Q,  L, Z) :-
  is_list(A)                                     % if is_list(A), 
  -> Q = [A|R], bfs( s(s(N)), [B|P], R,  L, Z)   % then      enqueue A, 
  ;  L = [A|R], bfs(   s(N),  [B|P], Q,  R, Z).  % otherwise produce A

The first argument is the distance between read and write point on the queue.第一个参数是队列上读写点之间的距离。 When they meet the queue has become exhausted and we stop.当他们遇到队列时,我们已经筋疲力尽了。 Both the input queue and the output list are maintained as difference list pairs of head and tail variables.输入队列和输出列表都作为头尾变量的差异列表对进行维护。

Trying it out:尝试一下:

12 ?- bfs( [[[6]],1,2,[4,[[[[[7]]]]],5],3], A).
A = [1, 2, 3, 4, 5, 6, 7] .

You will need to augment it to skip the non-lists in the top level.您需要对其进行扩充以跳过顶层的非列表。

A solution that uses an "open list" to append the elements encountered while walking the list-of-lists, which is essentially a tree, in prefix fashion.一种解决方案,它使用“打开列表”以前缀方式附加在遍历列表列表(本质上是一棵树)时遇到的元素。

The indicated examples indicate that non-list elements at depth 0 shall be discarded, and the other elements sorted by depth.所示示例表明深度为 0 的非列表元素将被丢弃,其他元素按深度排序。 However, no precise spec is given.但是,没有给出精确的规格。

Indeed, one would expect the result of flattening事实上,人们会期待扁平化的结果

[[[[a]],b,[c]],d,e,[f]]

to be成为

[b,f,c,a]

via the "sorted-by-depth" pair list of Depth-Value pairs:通过深度值对的“按深度排序”对列表:

[3-a,1-b,2-c,1-f]

But the question poster requests this result instead:但是问题发布者要求这个结果:

[f, a, b, c]

I don't really know whether this is an error or not.我真的不知道这是否是一个错误。

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

Some plunit tests:一些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).

And so:所以:

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

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

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