【问题标题】:How do I delete all the sub-lists from a list?如何从列表中删除所有子列表?
【发布时间】:2013-09-28 11:25:43
【问题描述】:

我想从列表列表中删除所有包含[['One', _], _] 的列表。我创建了以下子句delete_all,它始终有效,但我的情况除外:

delete_all(_,[],[]) :- !.
delete_all(X,[X|Tail],List) :-
    !,
    delete_all(X,Tail,List).
delete_all(X,[A|Tail],[A|List]) :-
    delete_all(X,Tail,List).

示例:(这很好用)

?- delete_all(3,[3,4,3,5,3],K).
K = [4, 5] .

但这效果不佳:

delete_all([['One', _], _], [[['One', 'Six'], 94],
    [['One', 'Ten'], 13], [['Two', 'Nine'], 35]], Y).
Y = [[['One', 'Ten'], 13], [['Two', 'Nine'], 35]].

为什么只删除第一个元素?有什么问题?

【问题讨论】:

    标签: prolog


    【解决方案1】:

    好吧,为了测试,这是一个有效的:

    delete_all(E, L, R) :- findall(X, (member(X, L), X \= E), R).
    

    我认为您的代码不起作用,因为它实例化 X,然后禁止进一步的匹配。delete/3 的文档(这就是您所追求的,只是交换参数)状态问题够清楚了。

    你应该改变你的第一个子句

    delete_all(X,[E|Tail],List):-
        \+ X \= E, !, delete_all(X,Tail,List).
    

    【讨论】:

      【解决方案2】:

      我想问题在于您的第一个术语(您正在搜索的模式)包含变量,并且当您扫描列表时,这些变量“unify”与列表元素。一旦您传递了一个匹配的元素,模式中的变量就会被实例化为该元素中相应术语的值,从而防止进一步匹配。

      一种可能的解决方案是检查您的模式和元素是否为unifiable,但最终没有统一它们。

      这样的东西可以满足你的需要:

      delete_all(_,[],[]):-!.
      
      delete_all(X,[H|Tail],List):-
          unifiable(X, H, _),
          !,
          delete_all(X,Tail,List).
      
      delete_all(X,[A|Tail],[A|List]):-
          delete_all(X,Tail,List).
      

      如果您使用的是 Yap,则必须导入 library(terms)

      :- use_module(library(terms)).
      

      另一种解决方案可能是使用棘手的not(not(X = H)) 而不是unifiable,它确实会检查您是否可以统一 H 和 X,如果您可以内部不阻止实例化并且第二个返回 true。

      更新:正如 CapelliC 所添加的,\+ X \= E 等于 not(not(X = E)),但现在具有更标准的语法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-12-09
        • 2017-09-16
        • 2018-04-22
        • 1970-01-01
        • 2016-08-26
        相关资源
        最近更新 更多