在列表中查找中间元素 [英] Prolog Finding middle element in List

查看:88
本文介绍了在列表中查找中间元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用序言谓词并查找给定列表的中间元素.我的想法是使用递归剪切列表的第一个元素和最后一个元素.不幸的是,我不知道如何正确处理递归调用.

I am trying to make use of prolog predicates and find middle element of a given list. My idea was to cut first and last element of list using recursion.Unfortunately I dont know how to handle recursion call properly.

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'). 

我将不胜感激.

推荐答案

您可以按照以下说明加强一些知识:

You can tighten up what you have quite a bit as follows:

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解决方案在这里也很好用:


A DCG solution also works well here:

% 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):


Another possible solution is to use SWI Prolog's append/2 predicate, which appends a list of lists (assuming you're using SWI):

middle(L, X) :-
    same_length(Left, Right),
    append([Left, [X], Right], L).

same_length([], []).
same_length([_|T1], [_|T2]) :- same_length(T1, T2).


在上述所有解决方案中,如果列表具有偶数个元素,则谓词将失败.由于这就是您原始解决方案的工作,因此我认为这是必需的.如果对偶数列表有特定要求,则需要明确说明.


In all of the above solutions, the predicate fails if the list has an even number of elements. Since that's what your original solution does, I assumed that's what is required. If there is a specific requirement for even lists, that needs to be stated clearly.

这篇关于在列表中查找中间元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆