我有一个序言。
我需要查看列表中的第一个项目,看看它的下列项目是否相同,直到它们不相同,并按第一项及其重复项分隔列表。例如,如果我的列表是a,a,a,b,c,它会将它分成第一个:a,a,a。第二:b,c。
我当前的解决方案有效,只是最后的匹配项进入第二个列表,而不是第一个。我似乎无法想出让它出现在第一个列表中的方法。
grab([],[],[]).
grab([A,A|L],[A|L2],Rest) :- grab([A|L],L2,Rest).
grab([A|L],Init,[A|L2]) :- grab(L,Init,L2).
答案 0 :(得分:4)
当前两个元素不同时,您不需要递归目标。
grab([], [], []).
grab([A,A|Rest], [A|As], L2):- !, grab([A|Rest], As, L2).
grab([A|Tail], [A], Tail).
答案 1 :(得分:3)
grab(Xs, Ys, Zs) :-
eqprefix(Xs, Ys, Zs).
eqprefix([],[],[]).
eqprefix([X],[],[X]).
eqprefix([X,Y|Xs], [], [X,Y|Xs]) :-
dif(X,Y).
eqprefix([X,X|Xs], [X|Ys], Zs) :-
eqprefix2([X|Xs], Ys, Zs).
eqprefix2([X], [X], []).
eqprefix2([X,Y|Xs], [X], [Y|Xs]) :-
dif(X,Y).
eqprefix2([X,X|Xs], [X|Ys], Zs) :-
eqprefix2([X|Xs], Ys, Zs).
?- eqprefix([a,a,a,b,c],Ys,Zs).
Ys = [a, a, a],
Zs = [b, c] ;
false.
?- eqprefix(Xs,[a,a,a],[b,c]).
Xs = [a, a, a, b, c] ;
false.
?- eqprefix([A,B,C,D,E],[a|Ys],[b,c]).
A = B, B = C, C = a,
D = b,
E = c,
Ys = [a, a] ;
false.
在您给出的定义中,您会得到许多不同的答案:
?- grab([a,a,a,b,c],Ys,Zs).
Ys = [a, a], Zs = [a, b, c]
; Ys = [a], Zs = [a, a, b, c]
; Ys = [a], Zs = [a, a, b, c]
; Ys = [], Zs = [a, a, a, b, c].
答案 2 :(得分:2)
以下是考虑what @Sarah wrote的另一种解决方案。鉴于此用法,grab/3
永远不会成为第一个或第二个参数的空列表。
grab([A], [A], []).
grab([A,B|Bs], [A], [B|Bs]) :-
dif(A,B).
grab([A,A|Xs], [A|As], Bs) :-
grab([A|Xs], As, Bs).
?- Xs = [A,B], grab(Xs,Ys,Zs).
Xs = [A, B], Ys = [A], Zs = [B], dif(A, B)
; Xs = Ys, Ys = [B, B], Zs = [], A = B
; false.
答案 3 :(得分:2)
以下是使用dcg的解决方案。最有趣的是这里使用非上下文的非终端。我将从一个过于笼统的尝试开始:
grab_tentative(Xs, Ys, Zs) :-
phrase((seq(Ys),seq(Zs)), Xs).
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
grab_tentative/3
确保Xs
由与Ys
连接的Zs
组成。这太笼统了,但已经包含了所有预期的解决方案。
?- Xs = [A,B,C], grab_tentative(Xs,Ys,Zs).
Xs = Zs, Zs = [A, B, C], Ys = []
; Xs = [A, B, C], Ys = [A], Zs = [B, C]
; Xs = [A, B, C], Ys = [A, B], Zs = [C]
; Xs = Ys, Ys = [A, B, C], Zs = []
; false.
第一个答案是Ys = []
,但是(原来是clarified by @Sarah),Ys
应该始终是非空列表,因此我们可以将答案限制为非空列表:
grab_tentative(Xs, Ys, Zs) :- Ys = [_|_], phrase((seq(Ys),seq(Zs)), Xs).
答案Xs = [A, B, C], Ys = [A, B], Zs = [C]
和Xs = Ys, Ys = [A, B, C], Zs = []
两者都允许A
和B
不同。所以我们必须补充说它们是相同的:
grab_tentative(Xs, Ys, Zs) :- Ys = [A|_], phrase((all_seq(=(A),Ys),seq(Zs)), Xs). all_seq(_, []) --> []. all_seq(C_1, [C|Cs]) --> [C], {call(C_1,C)}, all_seq(C_1, Cs).
现在,答案已经好一点了:
?- Xs = [A,B,C], grab_tentative(Xs,Ys,Zs).
Xs = [A, B, C], Ys = [A], Zs = [B, C]
; Xs = [B, B, C], A = B, Ys = [B, B], Zs = [C]
; Xs = Ys, Ys = [C, C, C], A = B, B = C, Zs = []
; false.
第一个答案包括A = B
。所以,它确实应该包含dif(A,B)
。为此,我们需要介绍这样的背景。这是做到这一点的方法。请注意,or_end//1
与[]//0
类似,只是它确保了一些额外条件。
grab_final(Xs, Ys, Zs) :- Ys = [A|_], phrase((all_seq(=(A),Ys), or_end(dif(A)), seq(Zs)), Xs). or_end(C_1) --> call(cond_or_end(C_1)). % interface to predicates cond_or_end(_C_1, [], []). cond_or_end(C_1, [E|Es], [E|Es]) :-
现在,答案如预期:
?- Xs = [A,B,C], grab_final(Xs, Ys, Zs).
Xs = [A, B, C], Ys = [A], Zs = [B, C], dif(A, B)
; Xs = [B, B, C], A = B, Ys = [B, B], Zs = [C], dif(B, C)
; Xs = Ys, Ys = [C, C, C], A = B, B = C, Zs = []
; false.