【问题标题】:Get elements of arbitrary nested lists获取任意嵌套列表的元素
【发布时间】:2022-10-05 03:56:59
【问题描述】:

我正在 SWI-Prolog 中寻找一些谓词来获取一些任意嵌套列表的元素。意味着,如果我例如有清单:

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

我得到结果:

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

标签: list nested prolog swi-prolog


【解决方案1】:

SWI 内置谓词flatten/2 取决于第一个参数的实例化。因此,它会导致完全不相关的行为:

?-         flatten(X,[]).
   false.
?- X = [], flatten(X,[]).
   X = [].
?- X = [[],[]], flatten(X,[]).
   X = [[], []].
?- X = [[]|[]], flatten(X,[]).
   X = [[]].

请注意,有无限多个X 可以使flatten(X,[]) 成功。如果您希望这是一个关系,则有两种选择,要么枚举所有此类解决方案,要么产生实例化错误,要么不终止(比不正确的答案更好),或者适当地延迟目标,或者产生一些约束,或者产生资源错误。哦,现在已经有 6 个选项了... ...以免我忘记,您也可以组合这些选项,例如首先生成一些答案替换,然后延迟目标,然后是约束,然后循环相当长的时间以最终生成一个资源错误。

在大多数此类情况下,最简单的方法是产生如下实例化错误:

flattened(T) -->
   {functor(T,_,_)},  % ensures instantiation
   (  {T = [E|Es]} -> flattened(E), flattened(Es)
   ;  {T = []} -> []
   ;  [T]
   ).
?- phrase(flattened([[]|[]]),Xs).
   Xs = [].
?- phrase(flattened([[]|_]),Xs).
   error(instantiation_error,functor/3).

【讨论】:

    【解决方案2】:

    正如@brebs 在他的评论中提到的,使用预定义谓词flatten/2

    % ?- flatten([[a,b], c, [d, [e, f]]], R).
    %     R = [a, b, c, d, e, f]
    

    这种用户定义的实现类似于预定义的实现[1]

    my_flatten([],[]).
    my_flatten([H|T], [H|Res]) :- \+ is_list(H), my_flatten(T, Res), !.
    my_flatten([H|T], Res) :- my_flatten(H, Res). % H is list.
    

    [1]除了my_flatten(X,non_list) 等非终止的情况。和喜欢my_flatten([X],[1,2,3,4])。感谢@false 评论

    【讨论】:

    • 类似于预定义的除了像my_flatten(X,non_list).这样的不终止的情况和像my_flatten([X],[1,2,3,4]).这样的缺乏坚定性的情况
    • @false,对,这就是我将其描述为“相似”的原因。我已将您的评论添加到答案中作为补充,谢谢
    • 还有许多其他不同类型的案例,例如my_flatten([[a|b]],Xs).
    【解决方案3】:

    这是使用底部描述的谓词获得的结果。

    % Lis= [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]],
    % flat_lvl(Lis, FlatLis, 2).
    %
    % ---> FlatLis = [e1, e2, e3, e4, e5, e6, e7, e8, e9]
    
    
    % Lis= [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]],
    % flat_lvl(Lis, FlatLis, 1).
    %
    % ---> FlatLis = [e1, e2, [e31, e32], e4, e5, e6, e7, e8, e9]
    
    
    % Lis= [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]],
    % flat_lvl(Lis, FlatLis, 0).
    %
    % ---> FlatLis = [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]]
    

    将具有指定级别的列表展平的谓词如下:

    flat_lvl([],[],_).
    flat_lvl([LisH| LisT], FlatLis, DeepLvl):-
        Lvl is DeepLvl - 1, Lvl >= -1,
        (flat_lvl(LisH, FlatH, Lvl); FlatH= [LisH]),
        flat_lvl(LisT, FlatTail, DeepLvl),
        append(FlatH, FlatTail, FlatLis), !.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-01
      • 2015-10-15
      • 1970-01-01
      • 1970-01-01
      • 2023-02-04
      • 2014-01-23
      • 2014-12-13
      • 1970-01-01
      相关资源
      最近更新 更多