如何从prolog列表中删除每个子列表?

时间:2015-03-29 05:01:16

标签: list prolog prolog-dif

这是从给定列表中删除或删除元素的代码:

remove_elem(X,[],[]). 
remove_elem(X,L1,L2) :-
   L1 = [H|T],
   X == H,
   remove_elem(X,T,Temp),
   L2 = Temp. 
remove_elem(X,L1,L2) :- 
   L1 = [H|T],
   X \== H, 
   remove_elem(X,T,Temp),
   L2 = [H|Temp].

如何修改它,以便我可以从列表中删除每个子列表?

当我尝试将一个列表放在一个元素中时,它只删除该元素并且只删除一次。

应该是这样的:

?- remove([1,2],[1,2,3,4,1,2,5,6,1,2,1],L).   
L = [3,4,5,6,1].                        % expected result

3 个答案:

答案 0 :(得分:1)

这种逻辑上纯粹的实现基于谓词if_/3 and (=)/3

首先,我们构建了prefix_of/2的确定版本:

prefix_of_t([],_,true).
prefix_of_t([X|Xs],Zs,T) :-
   prefix_of_t__aux(Zs,X,Xs,T).

prefix_of_t__aux([],_,_,false).
prefix_of_t__aux([Z|Zs],X,Xs,T) :-
   if_(X=Z, prefix_of_t(Xs,Zs,T), T=false).

然后,转到主谓词list_sublist_removed/3

list_sublist_removed([],[_|_],[]).
list_sublist_removed([X|Xs],[L|Ls],Zs) :-
    if_(prefix_of_t([L|Ls],[X|Xs]),                 % test
        (Zs = Zs0,     append([L|Ls],Xs0,[X|Xs])),  % case 1
        (Zs = [X|Zs0], Xs0 = Xs)),                  % case 2
    list_sublist_removed(Xs0,[L|Ls],Zs0).

关于list_sublist_removed/3的递归条款的一些操作说明:

  1. 首先(测试),我们检查[L|Ls]是否是[X|Xs]的前缀。

  2. 如果它存在(案例1),我们将其[X|Xs]剥离Xs0并向Zs添加任何内容。

  3. 如果不存在(案例2),我们将X关闭[X|Xs]并将X添加到Zs

  4. 我们对[X|Xs]的剩余部分进行了递归,直到不再需要处理任何项目为止。


  5. 转发一些疑问!

    1. 您在问题中提供的用例:

      ?- list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],[1,2],L).
      L = [3,4,5,6,1].                           % succeeds deterministically
      
    2. 尝试查找已删除的子列表的两个查询:

      ?- list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],Sub,[  3,4,5,6,1]).
      Sub = [1,2] ? ;
      no
      
      ?- list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],Sub,[1,3,4,5,6,1]).
      no
      
    3. 接下来,让我们在此查询中找到合适的Ls

         
      ?- list_sublist_removed(Ls,[1,2],[3,4,5,6,1]).
      % a lot of time passes ... and nothing happens!
      

      非终结!这是不幸的,但在预期之内,因为解决方案集是无限的。但是,通过先验约束Ls的长度,我们可以获得所有预期结果:

      ?- length(Ls,_), list_sublist_removed(Ls,[1,2],[3,4,5,6,1]).
        Ls = [      3,4,5,6,1]     ?
      ; Ls = [1,2,  3,4,5,6,1]     ?
      ; Ls = [3, 1,2, 4,5,6,1]     ?
      ; Ls = [3,4, 1,2, 5,6,1]     ?
      ; Ls = [3,4,5, 1,2, 6,1]     ?
      ; Ls = [3,4,5,6, 1,2, 1]     ?
      ; Ls = [3,4,5,6,1, 1,2 ]     ?
      ; Ls = [1,2, 1,2, 3,4,5,6,1] ? ...
      

答案 1 :(得分:1)

受@ CapelliC实施的启发,我编写了以下代码 and_t/3

append_t([]    ,Ys,Ys, true).
append_t([X|Xs],Ys,Zs,Truth) :-
   append_aux_t(Zs,Ys,Xs,X,Truth).

append_aux_t([]    ,_ ,_ ,_,false).     % aux pred for using 1st argument indexing
append_aux_t([Z|Zs],Ys,Xs,X,Truth) :-
   and_t(X=Z, append_t(Xs,Ys,Zs), Truth).

一个append_t/4目标可以取代两个prefix_of_t/3append/3目标。

正因为如此,list_sublist_removed/3的实现比以前更简单

list_sublist_removed([]    ,[_|_] ,[]).
list_sublist_removed([X|Xs],[L|Ls],Zs) :-
    if_(append_t([L|Ls],Xs0,[X|Xs]),
        (Zs =    Zs0 , Xs1 = Xs0),
        (Zs = [X|Zs0], Xs1 = Xs)),
    list_sublist_removed(Xs1,[L|Ls],Zs0).

还是确定性的?

?- list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],[1,2],L).
L = [3,4,5,6,1].

是的!以下怎么样?

?-  list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],X,[3,4,5,6,1]).
X = [1,2] ;                             % succeeds with useless choice-point
false.

不。所以仍有改进空间......

答案 2 :(得分:0)

<rant>

这么多年我研究Prolog,它仍然值得一些惊喜......你的问题很难解决,当你知道列表库,并且你有一个特定的模式(就像你发布的那个例子)。但也可能也很复杂,如果基于@false建议(if_ / 3和朋友)的@repeat提出的方法可以被移植到我身上,我也不清楚。平原,老Prolog(a-la Clocksin-Mellish,只是说)。

</rant>

基于老派Prolog

的解决方案,一直不容易找到
list_sublist_removed(L, S, R) :-
    append([A, S, B], L),
    S \= [],
    list_sublist_removed(B, S, T),
    append(A, T, R),
    !
    ; L = R.

一些测试:

?- list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],[1,2],L).
L = [3, 4, 5, 6, 1].

?- list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],X,[3, 4, 5, 6, 1]).
X = [1, 2].

?- length(X,_), list_sublist_removed(X,[1,2],[3, 4, 5, 6, 1]).
X = [3, 4, 5, 6, 1] ;
X = [3, 4, 5, 6, 1, 2, 1] ...