簡體   English   中英

Prolog - 如何從列表中刪除 N 個成員

[英]Prolog - How to remove N number of members from a list

所以我正在創建一個名為 removeN(List1, N, List2) 的謂詞。 它的基本功能應該是這樣的:

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

List2 = [o].

第一個參數是一個包含許多相同成員的列表([o, o, o] 或 [x, x, x])。 第二個參數是您要刪除的成員數,第三個參數是已刪除成員的列表。

我應該怎么做,我正在考慮使用某種長度。

提前致謝。

另一種方法是使用append/3length/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 ,則第一個列表的頭部必須等於引用元素(第 4 個參數)並且該關系也必須適用於尾部:

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,但我們基本上什么都不做。 在 index 等於 N 后,我們通過附加源列表中的所有剩余元素來開始構建輸出列表。

無效,但您可能仍然對該解決方案感興趣,因為它演示了非常強大的 foldl 謂詞的用法,該謂詞可用於解決范圍廣泛的列表處理問題。

倒計時應該可以正常工作

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

這對我有用。 我認為這是最簡單的方法。 trim(L,N,L2) L是列表, N是元素的數量。

trim(_,0,[]).
trim([H|T],N,[H|T1]):-N1 is N-1,trim(T,N1,T1).

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM