Prolog从列表PROLOG提供的项目之间获取项目

时间:2015-03-19 19:58:20

标签: list prolog

我正在尝试在prolog中构建一个列表函数,希望能够执行以下操作;

split(1, 4, [1, 2, 3, 4]). [2, 3]
split(2, 4, [1, 2, 3, 4, 5]). [3]

即它会将所有项目放在列表中,这些项目出现在提供的两个值之间。

我尝试了什么;

split(Start, Finish, List) :- append(List, _, [Start|Xs]),
                              append([Finish|Xs], _, List).

我似乎永远不会让它发挥作用!我是prolog的新手所以请相对亲切!!

由于

修改

好的,我有一个解决方案,想知道它是否可以改进。解决方案如下,

% Split a list at a specified index
split(List, Index, Front, Back) :-
  length(Front, Index),
  append(Front, Back, List).

% Get list items inbetween members
inbetween(List, From, To, Result) :- 
  nth1(FromI, List, From),
  nth0(ToI, List, To),
  split(List, FromI, _, List1),
  split(List, ToI, _, List2),
  subtract(List1, List2, Result).

正如您所看到的,我按照评论中的建议进行了调整并稍微调整了一下。这有什么改进吗?

谢谢,(甚至可能在一个谓词中?)

示例

 inbetween([1,2,3,4,5,6], 2, 5, Result). % [3,4]
 inbetween([a,b,c,d,e,f], a, e, Result). % [b,c,d]

1 个答案:

答案 0 :(得分:2)

我认为您提出的解决方案很有趣,只需要进行一些小调整即可使其正常工作:

% Split a list at a specified index
split(List, Index, Front, Back) :-
    length(Front, Index),
    append(Front, Back, List).

% Get list items inbetween members
inbetween(List, From, To, Result) :-
    nth1(FromI, List, From),
    split(List, FromI, _, List1),
    nth0(ToI, List1, To),
    split(List1, ToI, Result, _).

split/4谓词与您所拥有的不变。我修改了inbetween/4主谓词,以便首先找到From之后的所有内容,然后使用该结果并找到To之前的所有内容最终结果。

| ?-  inbetween([a,b,c,a,x,b,e,f], a, b, L).

L = [] ? ;

L = [b,c,a,x] ? ;

L = [x] ? ;

(1 ms) no

<小时/> 使用append/3的较短版本为:

betwixt2(List, A, B, Result) :-
    append(_, [A|T], List),
    append(Result, [B|_], T).

<小时/> 另一种基于递归而不使用库调用的方法是:

inbetween(List, A, B, Result) :-
    split_left(List, A, R),
    split_right(R, B, Result).

split_left([X|T], X, T).
split_left([_|T], X, R) :- split_left(T, X, R).
split_right([X|_], X, []).
split_right([H|T], X, [H|R]) :- split_right(T, X, R).

<小时/> 最后,这是一个有趣,简洁的解决方案,我在评论时没有考虑过,使用更透明的DCG:

betwixt(A, B, M) --> anything, [A], collect(M), [B], anything.

anything --> [].
anything --> [_], anything.

collect([]) --> [].
collect([H|T]) --> [H], collect(T).

inbetween(List, A, B, Result) :- phrase(betwixt(A, B, Result), List).

在这种情况下,DCG很好地说明了发生了什么,结果与上面相同。为简洁起见,我还可以在第一个条款中使用collect(_)代替anything,但不想浪费未使用的参数。

要使用记入@false的好记谱,我们可以使用...作为术语,如下所示:

betwixt(A, B, M) --> ..., [A], collect(M), [B], ... .

... --> [].
... --> [_], ... .

collect([]) --> [].
collect([H|T]) --> [H], collect(T).