所以我做了一個名爲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