2017-10-10 67 views
2

所以我做了一个名为removeN(列表1,N,列表2)谓语删除成员的N多。应该基本上起到这样的:序言 - 如何从列表

removeN([o, o, o, o], 3, List2). 

List2 = [o]. 

第一个参数是与许多相同的部件的列表([O,O,O-]或[X,X,X])。第二个参数是要删除的成员数量,第三个参数是已删除成员的列表。

我应该如何去了解这一点,我想使用某种类型的长度。

在此先感谢。

+0

它应该做的,如果列表中的成员有什么不同? –

+0

应该失败,但它不是很重要,因为提供的列表会一直为O的列表。 – PEREZje

回答

1

倒计时应该正常工作

removeN([],K,[]) :- K>=0. 
removeN(X,0,X). 
removeN([_|R],K,Y) :- K2 is K-1, removeN(R,K2,Y). 
+0

编辑完成后,出现了一些小错误。 – Armatorix

+4

我会建议使用'SUCC(K2,K1)',而不是'是/ 2',因为它成功在两个方向。尽管这不是很重要。 –

2

另一种方法是使用append/3length/2

remove_n(List, N, ShorterList) :- 
    length(Prefix, N), 
    append(Prefix, ShorterList, List). 
3

想想谓语应说明。它是一个列表,一个数字和一个列表之间的关系,它或者等于第一个或者缺少指定数量的第一个元素。让我们为它选择一个描述性的名字,比如说list_n_removed/3。既然你想要删除了一些相同的元素,让我们保持列表的头比较的原因,所以list_n_removed/3只是调用谓词,并与和额外的参数另一个谓词,姑且称之为list_n_removed_head/4,描述了实际关系:

list_n_removed([X|Xs],N,R) :- 
    list_n_removed_head([X|Xs],N,R,X). 

谓词list_n_removed_head/4具有处理两个不同的情况:要么N=0,则第一和第三个参数是相同的列表或N>0,则第一列表的头部必须等于对于参考元件(第四参数)和关系必须保持尾部,以及:

list_n_removed_head(L,0,L,_X). 
list_n_removed_head([X|Xs],N,R,X) :- 
    N>0, 
    N0 is N-1, 
    list_n_removed_head(Xs,N0,R,X). 

现在让我们来看看它是如何工作的。您的示例查询产生所期望的结果:

?- list_n_removed([o,o,o,o],3,R). 
R = [o] ; 
false. 

如果前三个元素是不相等谓词失败:

?- list_n_removed([o,b,o,o],3,R). 
false. 

如果列表的长度等于N结果是空列表:

?- list_n_removed([o,o,o],3,R). 
R = []. 

如果列表的长度比N越小谓词失败:

?- list_n_removed([o,o],3,R). 
false. 

如果N=0两个列表是相同的:

?- list_n_removed([o,o,o,o],0,R). 
R = [o, o, o, o] ; 
false. 

如果N<0谓词失败:

?- list_n_removed([o,o,o,o],-1,R). 
false. 

谓词可以在其他方向上使用,以及:

?- list_n_removed(L,0,[o]). 
L = [o] ; 
false. 

?- list_n_removed(L,3,[o]). 
L = [_G275, _G275, _G275, o] ; 
false. 

然而,如果第二申辩是可变的:

?- list_n_removed([o,o,o,o],N,[o]). 
ERROR: >/2: Arguments are not sufficiently instantiated 

这可以通过使用CLP(FD)来避免。考虑以下变化:

:- use_module(library(clpfd)).    % <- new 

list_n_removed([X|Xs],N,R) :- 
    list_n_removed_head([X|Xs],N,R,X). 

list_n_removed_head(L,0,L,_X). 
list_n_removed_head([X|Xs],N,R,X) :- 
    N #> 0,         % <- change 
    N0 #= N-1,        % <- change 
    list_n_removed_head(Xs,N0,R,X). 

现在上面的查询提供了预期的结果:

?- list_n_removed([o,o,o,o],N,[o]). 
N = 3 ; 
false. 

一样最普通的查询:

?- list_n_removed(L,N,R). 
L = R, R = [_G653|_G654], 
N = 0 ; 
L = [_G653|R], 
N = 1 ; 
L = [_G26, _G26|R], 
N = 2 ; 
L = [_G26, _G26, _G26|R], 
N = 3 ; 
. 
. 
. 

的其他查询上述收益率相同的答案与CLP(FD)版本。

2

使用foldl/4替代解决方案:

remove_step(N, _Item, Idx:Tail, IdxPlusOne:Tail) :- 
    Idx < N, succ(Idx, IdxPlusOne). 
remove_step(N, Item, Idx:Tail, IdxPlusOne:NewTail) :- 
    Idx >= N, succ(Idx, IdxPlusOne), 
    Tail = [Item|NewTail]. 

remove_n(List1, N, List2) :- 
    foldl(remove_step(N), List1, 0:List2, _:[]). 

这里的想法是要经过列表,同时跟踪当前元素的索引。虽然元素索引低于指定的数字N,但我们基本上什么都不做索引等于N后,我们通过附加源列表中所有剩余的元素来开始构建输出列表。

效果不理想,但你仍然可能感兴趣的解决方案,因为它说明了一个非常强大与foldl谓词,它可以用来解决范围广泛的列表处理问题的用法。