Prolog:如何从列表中删除子列表? (后续问题)

时间:2018-10-11 22:50:37

标签: list prolog

Prolog的新手,对Prolog中的递归不太了解,因此我不确定如何从已经考虑的列表中删除元素。

这是我上一个问题的后续问题: Prolog: How do you iterate between two lists (nest for-loop)?

我有两个列表:

stringList([hello, hi], [bye,later], X).

函数stringList如下所示:

stringList(As, Bs, [A,B]) :-
  member(A, As),
  member(B, Bs).

这将产生输出:

X = [hi, bye] ;
X = [hi, later] ;
X = [hello, bye] ;
X = [hello, later].

现在,我要从两个列表中删除子列表。例如,如果X = [hi, later],我想打个招呼,然后下一个X = [hello, bye]。当我的清单很大时,这一点变得更加重要。

我知道我需要递归,所以我创建了基本案例:

stringList([],[],[]).

1 个答案:

答案 0 :(得分:1)

一种方法是使用findall/3delete/3谓词。当前,您的stringList/3一次生成一个解决方案,因此您需要使用findall/3将所有这些解决方案收集到一个列表中,然后删除所需的任何内容:

deleteSublist(As, Bs, Elem, L):- 
       findall([X,Y], stringList(As, Bs, [X,Y]), L1),
       delete(L1, Elem, L).

示例:

?- deleteSublist([hello, hi], [bye,later], [hi,_], L).
L = [[hello, bye], [hello, later]].

在上面的示例中,您要删除的元素可能只是[hi,bye],但是我们使用[hi,_]删除所有出现的hi。

现在要回答您的问题,可以使用递归轻松完成,但是要使用递归,您需要将所有解决方案都放在一个列表中,以便稍后您可以从该列表中递归提取元素。上述解决方案中的递归部分隐藏在delete/3内置的内部。因此,如果您想使用自己的递归解决方案,只需编写自己的delete/3递归定义即可(我认为必须在堆栈溢出中询问该定义,以便您可以搜索或搜索它……)

另一件事,如果您希望您的解决方案一次像stringList/3谓词中那样生成一个解决方案,那么您也可以在下面使用这种简单方法:

?- stringList([hello, hi], [bye,later], X),(X \= [hi,_]).
X = [hello, bye] ;
X = [hello, later] ;
false.

在上面的方法中,我们利用了\=在比较[hi,bye] \= [hi,_]时失败的优点,而如果您使用纯dif/2则将成功:

?- stringList([hello, hi], [bye,later], X),dif(X,[hi,_]).
X = [hello, bye] ;
X = [hello, later] ;
X = [hi, bye] ;
X = [hi, later].

因此,使用dif / 2时,您将需要更详细的限制:

?- stringList([hello, hi], [bye,later], X),dif(X,[hi,bye]), dif(X,[hi,later]).
X = [hello, bye] ;
X = [hello, later] ;
false.