我正在尝试编写Prolog代码,找到列表中的 n -th元素。 我编写了下面的代码,但它没有正确地返回元素。
match([Elem|Tail],Num,Num,Elem).
match([Elem|Tail],Num,C,MatchedNumber):-
match(Tail,Num,N,Elem),
C is N+1.
在第一行我说,如果请求的元素号等于counter,则将当前列表的第一个元素赋给名为MatchedNumber
的变量。此代码返回Num
和Counter
权限,但我不知道为什么当我想将MatchedNumber
设置为Elem
时,它始终返回列表的第一个元素
1:这段代码出了什么问题? 2:我怎么说而不是显示匹配的号码,将其从列表中删除?
答案 0 :(得分:7)
首先,有一个内置nth0/3
:
?- nth0(0,[a,b,c],X).
X = a.
?- nth0(1,[a,b,c],X).
X = b.
?- nth0(2,[a,b,c],X).
X = c.
?- nth0(3,[a,b,c],X).
false.
问题在于归纳案例:
match([Elem|Tail],Num,Counter,MatchedNumber):-
match(Tail,Num,N,Elem),
C is N+1.
Prolog对C
一无所知,所以最后一句话不会强迫Prolog返回 i -th元素。它可以简单地返回任何元素,因为N
将在递归调用中与Num
匹配,然后将C
设置为Num+1
,但这不是问题,因为{{ 1}}不受任何约束。
解决此问题的更好方法是使用减量计数器:
C
示例强>:
match([H|_],0,H) :-
!.
match([_|T],N,H) :-
N > 0, %add for loop prevention
N1 is N-1,
match(T,N1,H).
因此,基本情况是索引为?- match([a,b,c,d,e],0,X).
X = a.
?- match([a,b,c,d,e],1,X).
X = b.
?- match([a,b,c,d,e],2,X).
X = c.
?- match([a,b,c,d,e],3,X).
X = d.
?- match([a,b,c,d,e],4,X).
X = e.
?- match([a,b,c,d,e],5,X).
false.
,在这种情况下,您返回 head ,否则您将查询 i-1 -th元素尾巴这也是一种更具说明性的方法。
这种方法也使用尾递归,这通常会显着提升性能。
un-Prolog 使用迭代器和绑定,通常使用反向迭代器。
但您可以按如下方式修改谓词:
0
所以有一些错误:
match([Elem|_],Num,Num,Elem) :-
!.
match([_|Tail],Num,Count,MatchedNumber) :-
Count < Num,
Count1 is Count+1,
match(Tail,Num,Count1,MatchedNumber).
:因为如果匹配,我们知道Prolog不应该尝试第二个; !
而不是MatchedNumber
; Elem
,Count < Num
的增量;和Count1 is Count+1
替换所有不使用的变量。然后是一个例子:
_
但如前所述,传递额外的参数等是无效的。
可以使用几乎等效的方法从列表中删除 i -th元素:
?- match([a,b,c,d,e],0,0,X).
X = a.
?- match([a,b,c,d,e],1,0,X).
X = b.
?- match([a,b,c,d,e],2,0,X).
X = c.
?- match([a,b,c,d,e],3,0,X).
X = d.
?- match([a,b,c,d,e],4,0,X).
X = e.
?- match([a,b,c,d,e],5,0,X).
false.
这里的基本情况再次是索引是removei([],_,[]).
removei([_|T],0,T) :-
!.
removei([H|T],N,[H|TR]) :-
N1 is N-1,
removei(T,N1,TR).
,在这种情况下,列表的尾部被删除(因此丢弃了头部)。归纳案例将列表的头部放在结果列表的头部,并依靠递归调用从尾部删除正确的项目。添加了另一个基本案例0
,因为 i 可能大于列表的长度,在这种情况下,此谓词不会删除任何项目。
示例强>
removei([],_,[]).
答案 1 :(得分:4)
要查找列表的第n个元素(n
相对于零),这样的事情应该足够了:
find_nth_element_of_list( 0 , X , [X|_] ) .
find_nth_element_of_list( N , X , [_|Xs] ) :-
N > 0 ,
N1 is N-1 ,
find_nth_element_of_list( N1 , X , Xs )
.
同样,要删除列表的第n个元素,这样的事情就足够了:
remove_nth_element_of_list( 0 , [_|Xs] , Xs ) . % at n=0, toss the head and unify the tail with the result set
remove_nth_element_of_list( N , [X|Xs] , [X|Ys] ) :- % at n>0, prepend the head to the result and recurse down.
N > 0 ,
N1 is N-1 ,
remove_nth_element_of_list( N1 , Xs , Ys )
.