所以我做了一个名为removeN(List1,N,List2)的谓词。它基本上应该是这样的:
removeN([o, o, o, o], 3, List2).
List2 = [o].
第一个参数是一个列表,其中包含许多相同的成员([o,o,o]或[x,x,x])。第二个参数是您要删除的成员数,第三个参数是包含已删除成员的列表。
我应该怎么做,我正在考虑使用某种长度。
提前致谢。
答案 0 :(得分: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)版本产生相同的答案。
答案 1 :(得分:2)
另一种方法是使用append/3
和length/2
:
remove_n(List, N, ShorterList) :-
length(Prefix, N),
append(Prefix, ShorterList, List).
答案 2 :(得分: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谓词的用法,它可以用来解决各种列表处理问题。
答案 3 :(得分:1)
倒计时应该可以正常工作
removeN([],K,[]) :- K>=0.
removeN(X,0,X).
removeN([_|R],K,Y) :- K2 is K-1, removeN(R,K2,Y).
答案 4 :(得分:0)
这对我有用。
我认为这是最简单的方法。
trim(L,N,L2)
。 L
是列表,N
是元素数。
trim(_,0,[]).
trim([H|T],N,[H|T1]):-N1 is N-1,trim(T,N1,T1).