2017-10-10 65 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謂詞,它可以用來解決範圍廣泛的列表處理問題的用法。