所以我做了一个名为removeN(列表1,N,列表2)谓语删除成员的N多。应该基本上起到这样的:序言 - 如何从列表
removeN([o, o, o, o], 3, List2).
List2 = [o].
第一个参数是与许多相同的部件的列表([O,O,O-]或[X,X,X])。第二个参数是要删除的成员数量,第三个参数是已删除成员的列表。
我应该如何去了解这一点,我想使用某种类型的长度。
在此先感谢。
所以我做了一个名为removeN(列表1,N,列表2)谓语删除成员的N多。应该基本上起到这样的:序言 - 如何从列表
removeN([o, o, o, o], 3, List2).
List2 = [o].
第一个参数是与许多相同的部件的列表([O,O,O-]或[X,X,X])。第二个参数是要删除的成员数量,第三个参数是已删除成员的列表。
我应该如何去了解这一点,我想使用某种类型的长度。
在此先感谢。
倒计时应该正常工作
removeN([],K,[]) :- K>=0.
removeN(X,0,X).
removeN([_|R],K,Y) :- K2 is K-1, removeN(R,K2,Y).
编辑完成后,出现了一些小错误。 – Armatorix
我会建议使用'SUCC(K2,K1)',而不是'是/ 2',因为它成功在两个方向。尽管这不是很重要。 –
另一种方法是使用append/3
和length/2
:
remove_n(List, N, ShorterList) :-
length(Prefix, N),
append(Prefix, ShorterList, List).
想想谓语应说明。它是一个列表,一个数字和一个列表之间的关系,它或者等于第一个或者缺少指定数量的第一个元素。让我们为它选择一个描述性的名字,比如说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)版本。
使用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谓词,它可以用来解决范围广泛的列表处理问题的用法。
它应该做的,如果列表中的成员有什么不同? –
应该失败,但它不是很重要,因为提供的列表会一直为O的列表。 – PEREZje