你能帮我解决一下吗?
编写一个三元谓词
delete_nth
,删除列表中的每个第n个元素。
样品运行:
?‐ delete_nth([a,b,c,d,e,f],2,L).
L = [a, c, e] ;
false
?‐ delete_nth([a,b,c,d,e,f],1,L).
L = [] ;
false
?‐ delete_nth([a,b,c,d,e,f],0,L).
false
我试过了:
listnum([],0).
listnum([_|L],N) :-
listnum(L,N1),
N is N1+1.
delete_nth([],_,_).
delete_nth([X|L],C,L1) :-
listnum(L,S),
Num is S+1,
( C>0
-> Y is round(Num/C),Y=0
-> delete_nth(L,C,L1)
; delete_nth(L,C,[X|L1])
).
答案 0 :(得分:4)
我的稍微奢侈的变种:
delete_nth(L, N, R) :-
N > 0, % Added to conform "?‐ delete_nth([a,b,c,d,e,f],0,L). false"
( N1 is N - 1, length(Begin, N1), append(Begin, [_|Rest], L) ->
delete_nth(Rest, N, RestNew), append(Begin, RestNew, R)
;
R = L
).
答案 1 :(得分:3)
让我们使用clpfd!为了多功能性和其他很多理由:
:- use_module(library(clpfd)).
我们根据if_/3
和(#>=)/3
定义delete_nth/3
:
delete_nth(Xs,N,Ys) :-
N #> 0,
every_tmp_nth_deleted(Xs,0,N,Ys).
every_tmp_nth_deleted([] ,_ ,_,[] ). % internal auxiliary predicate
every_tmp_nth_deleted([X|Xs],N0,N,Ys0) :-
N1 is N0+1,
if_(N1 #>= N,
(N2 = 0, Ys0 = Ys ),
(N2 = N1, Ys0 = [X|Ys])),
every_tmp_nth_deleted(Xs,N2,N,Ys).
示例查询:
?- delete_nth([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],2,Ys). Ys = [1,3,5,7,9,11,13,15] % succeeds deterministically
好的, little 更通用的东西怎么样?
?- delete_nth([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],N,Ys). N = 1 , Ys = [] ; N = 2 , Ys = [1, 3, 5, 7, 9, 11, 13, 15] ; N = 3 , Ys = [1,2, 4,5, 7,8, 10,11, 13,14 ] ; N = 4 , Ys = [1,2,3, 5,6,7, 9,10,11, 13,14,15] ; N = 5 , Ys = [1,2,3,4, 6,7,8,9, 11,12,13,14 ] ; N = 6 , Ys = [1,2,3,4,5, 7,8,9,10,11, 13,14,15] ; N = 7 , Ys = [1,2,3,4,5,6, 8,9,10,11,12,13, 15] ; N = 8 , Ys = [1,2,3,4,5,6,7, 9,10,11,12,13,14,15] ; N = 9 , Ys = [1,2,3,4,5,6,7,8, 10,11,12,13,14,15] ; N = 10 , Ys = [1,2,3,4,5,6,7,8,9, 11,12,13,14,15] ; N = 11 , Ys = [1,2,3,4,5,6,7,8,9,10, 12,13,14,15] ; N = 12 , Ys = [1,2,3,4,5,6,7,8,9,10,11, 13,14,15] ; N = 13 , Ys = [1,2,3,4,5,6,7,8,9,10,11,12, 14,15] ; N = 14 , Ys = [1,2,3,4,5,6,7,8,9,10,11,12,13, 15] ; N = 15 , Ys = [1,2,3,4,5,6,7,8,9,10,11,12,13,14 ] ; N in 16..sup, Ys = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15].
答案 2 :(得分:2)
编辑,纠正@CapelliC指出的错误,其中谓词在N = 0时成功。
我可以看到你的解决方案在哪里,但在这种情况下你不必费心这么多算术。我们可以通过从N重复向下计数直到列表为空来删除第N个元素。首先,快速说明风格:
如果您使用空格,换行符和正确放置括号,您可以帮助您的读者解析您的代码。您的最后一个条款在这种形式下更具可读性:
delete_nth([X|L], C, L1):-
listnum(L, S),
Num is S+1,
C>0 -> Y is round(Num/C),
Y=0 -> delete_nth(L, C, L1)
; delete_nth(L, C, [X|L1]).
现在查看你的代码,我不确定你是否打算写
( C>0 -> ( Y is round(Num/C),
Y=0 -> delete_nth(L, C, L1) )
; delete_nth(L, C, [X|L1])
).
或者如果你的意思是
C>0 -> Y is round(Num/C),
( Y=0 -> delete_nth(L, C, L1)
; delete_nth(L, C, [X|L1])
).
或者你可能在第二个条件之前错过了;
?无论如何,我建议采用另一种方法......
这看起来像是辅助谓词的工作!
通常,我们只需要一个简单的关系来构成一个查询,但解析查询并得到一个答案所需的计算过程需要一个更复杂的关系。在这些情况下,“说起来容易做起来难”。
我对此问题的解决方法如下:为了删除每个第n个元素,我们从N开始并向下计数到1.每次我们从N递减值时,我们将元素从原始列表移动到列表我们要保留的元素。当我们到达1时,我们丢弃原始列表中的元素,并再次从N开始倒计时。正如您所看到的,为了询问“放弃Kept
的每个N
元素导致的列表List
是什么?”我们只需要三个变量。但我回答这个问题,还需要另一个变量来跟踪从N
到1的倒计时,因为每次我们从List
开始,我们都需要问“什么是{{ 1}}?”一旦我们达到1,我们就需要能够记住Count
的原始值。
因此,我提供的解决方案依赖于辅助的4位谓词来进行计算,将3位谓词作为“前端”,即作为用于提出问题的谓词。
N
答案 3 :(得分:2)
请遵循病理学家的指导性答案和解释(+1)。我只是在解决方案上发布自己的赌注,因为?‐ delete_nth([a,b,c,d,e,f],0,L).
的同上解决方案存在问题。
delete_nth(L,C,R) :-
delete_nth(L,C,1,R).
delete_nth([],_,_,[]).
delete_nth([_|T],C,C,T1) :- !, delete_nth(T,C,1,T1).
delete_nth([H|T],N,C,[H|T1]) :- C<N, C1 is C+1, delete_nth(T,N,C1,T1).
产量
1 ?- delete_nth([a,b,c,d,e,f],2,L).
L = [a, c, e].
2 ?- delete_nth([a,b,c,d,e,f],1,L).
L = [].
3 ?- delete_nth([a,b,c,d,e,f],0,L).
false.
一个小问题(?):这段代码是确定性的,而明显发布的样本不是(你必须输入';'才能得到假结尾)。删除剪切将产生相同的行为。
一个有趣的 - imho - 一个班轮变体:
delete_nth(L,C,R) :- findall(E, (nth1(I,L,E),I mod C =\= 0), R).
但必须排除C == 0,以避免
ERROR: mod/2: Arithmetic: evaluation error: `zero_divisor'
答案 4 :(得分:1)
另一种方法,跟进@ user3598120最初的冲动来计算不受欢迎的第N个元素,并受到@Sergey Dymchenko玩具的启发。它使用exclude/3
删除基于1的索引处的所有元素,该索引是N
delete_nth(List, N, Kept) :-
N > 0,
exclude(index_multiple_of(N, List), List, Kept).
index_multiple_of(N, List, Element) :-
nth1(Index, List, Element),
0 is Index mod N.