我正在尝试在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]
答案 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).