我正在尝试使用prolog谓词并找到给定列表的中间元素。我的想法是使用递归来剪切列表的第一个和最后一个元素。很遗憾,我不知道如何正确处理递归调用。
delete_last(L, L1) :-
append(L1, [_], L).
delete_first(L,L1) :-
append([_],L1,L).
check_len(L) :-
length(L,LEN), \+ 1 is LEN.
delete_both([],_):-
false.
delete_both([_,_],_) :-
false.
delete_both([X],X):-
true, write('MidElement').
delete_both(L,L2) :-
delete_first(LT,L2), delete_last(L,LT),check_len(LT)
->write('here should be recursive call only when length is more than one').
如果有任何帮助,我将不胜感激。
答案 0 :(得分:3)
如果你检查了列表的长度,计算了中间元素的位置,那么它将节省大量的输入,然后遍历> em>用于获取该位置元素的列表。使用SWI-Prolog,这将是:
?- length(List, Len),
divmod(Len, 2, N, 1),
nth0(N, List, a).
List = [a], Len = 1, N = 0 ;
List = [_G2371, a, _G2377], Len = 3, N = 1 ;
List = [_G2371, _G2374, a, _G2380, _G2383], Len = 5, N = 2 . % and so on
此解决方案可确保列表具有奇数长度。如果您需要自己定义,可以看到documentation of divmod/4
。或者,如果列表不必具有奇数,长度,则只需使用N is Len div 2
。如果由于某种原因您不允许使用nth0/3
,那么实施它仍然比您尝试的更容易。
答案 1 :(得分:2)
你可以按照以下方式收紧你所拥有的东西:
delete_last(L, L1) :-
append(L1, [_], L).
delete_first([_|L], L).
% No need to check length of 1, since we only need to check
% if L = [X] in the caller, so we'll eliminate this predicate
%check_len(L) :-
% length(L, 1). % No need for an extra variable to check length is 1
% Clauses that yield false are not needed since clauses already fail if not true
% So you can just remove those
%
delete_both([X], X) :-
write('MidElement').
% Here you need to fix the logic in your main clause
% You are deleting the first element of the list, then the last element
% from that result and checking if the length is 1.
delete_both(L, X) :-
delete_first(L, L1), % Remove first and last elements from L
delete_last(L1, LT),
( LT = [X] % Check for length of 1
-> true
; delete_both(LT, X) % otherwise, X is result of delete_both(LT, X)
).
结果:
| ?- delete_both([a,b,c,d,e], X).
X = c
yes
| ?- delete_both([a,b,c,d,e,f], X).
no
<小时/> DCG解决方案也适用于此:
% X is the middle if it is flanked by two sequences of the same length
%
middle(X) --> seq(N), [X], seq(N).
seq(0) --> [].
seq(N) --> [_], { N #= N1 + 1 }, seq(N1).
middle(List, X) :- phrase(middle(X), List).
结果:
| ?- middle([a,b,c,d,e], X).
X = c ? ;
(1 ms) no
| ?- middle(L, a).
L = [a] ? ;
L = [_,a,_] ? ;
L = [_,_,a,_,_] ?
...
<小时/> 另一种可能的解决方案是使用SWI Prolog的
append/2
谓词,它附加一个列表列表(假设您正在使用SWI):
middle(L, X) :-
same_length(Left, Right),
append([Left, [X], Right], L).
same_length([], []).
same_length([_|T1], [_|T2]) :- same_length(T1, T2).
<小时/> 在所有上述解决方案中,如果列表具有偶数个元素,则谓词将失败。由于这是您的原始解决方案所做的,我认为这是必需的。如果对偶数列表有特定要求,则需要明确说明。