将列表分成两半

时间:2011-11-18 00:34:35

标签: list prolog

我需要定义除法,以便列表[1,2,3,4,5]分为:

a = [1,2,3}

b = [4,5]

我收到的错误是"Arguments are not sufficiently instantiated",我对语言知之甚少,无法弄清楚我的问题是什么,或者我的设计是否正确。任何指导都将不胜感激。

所以这就是我到目前为止所拥有的:

append([],L2,L2).
append([H|T],L2,[H|L3]) :- append(T,L2,L3).

lengthIs([],N).
lengthIs([H|T],N) :- lengthIs(T,M), N is M+1.

divide([],[],[]).
divide([H|T],L2,L3) :-
   (  lengthIs(L2, M) < lengthIs(L1,N)/2
   -> divide(T, append(L2, H, X), L3)
   ;  divide(T, L2, append(L3,H,Y))
   ).

7 个答案:

答案 0 :(得分:8)

让我们给谓词一个更多的关系名称:list_half_half/3

list_half_half(Xs, Ys, Zs) :-
   length(Xs, N),
   H is N - N // 2,
   length(Ys, H),
   append(Ys, Zs, Xs).
几乎所有最近的Prolog都预先定义了

length/2append/3

这是GNU Prolog:

| ?- append(L,_,[a,b,c,d]), list_half_half(L,H1,H2).

H1 = []
H2 = []
L = [] ? ;

H1 = [a]
H2 = []
L = [a] ? ;

H1 = [a]
H2 = [b]
L = [a,b] ? ;

H1 = [a,b]
H2 = [c]
L = [a,b,c] ? ;

H1 = [a,b]
H2 = [c,d]
L = [a,b,c,d]

答案 1 :(得分:5)

这是符合大多数Prolog实施规范的最有效解决方案:

divide(L, A, B) :-
    divide1(L, L, A, B).

divide1([], L, [], L).
divide1([_|T], [H|L], [H|A], B) :-
    divide2(T, L, A, B).

divide2([], L, [], L).
divide2([_|T], L, A, B) :-
    divide1(T, L, A, B).

如果您不介意哪些元素进入子列表,只要它们具有相似的长度(如Konstantin Weitz帖子中的解决方案),那么您可以使用:

divide([], [], []).
divide([H|T], [H|A], B) :- divide(T, B, A).

答案 2 :(得分:4)

append是一个预定义的谓词,因此可能是问题所在:http://en.wikibooks.org/wiki/Prolog/Lists#The_append_predicate

你也从未在lengthIs中定义'N' - 你需要将空列表设置为0,而不是N / 可能还有尺寸功能

下划线告诉Prolog我们不关心谓词定义中的那一点。

这样的事情应该有效

divide(L1,L2,L3):- append(L2,L3,L1), 
                   samesize(L2,L3).
divide(L1,L2,L3):- append(L2,L3,L1), 
                   onebigger(L2,L3).
samesize(A,B):-    size(A,N),
                   size(B,N).
onebigger(A,[_|T]):-   size(A,N), 
                   size(T,N).
size([],0).
size([H|T],N):-    size(T,M+1).

答案 3 :(得分:2)

无需检查尺码。就这样做:

div([],[],[]).
div([A],[A],[]).
div([A,B|T],[A|X],[B|Y]) :- div(T,X,Y).

答案 4 :(得分:2)

此代码(lengthIs(L2, M) < lengthIs(L1,N)/2 -> ...)的效果肯定不是您所期望的:它不会比较数字,而是比较术语。你应该这样写:

lengthIs(L2, M), lengthIs(L1, N), M < N/2 -> ...

另一个错误的错误:lengthIs / 2的第一个句子应该是

lengthIs([],0).

答案 5 :(得分:0)

另一个答案, 虽然使用Backtracking很多,但性能不是很好。 假定appendlength是预定义的:

divide(A,B,C):-
    append(B,C,A),
    length(B,B_Length),
    length(C,C_Length),
    (B_Length = C_Length;
        B_Length =:= C_Length +1).

哦,对不起,只是看到这是对菲利普怀特豪斯答案的一种改述。

答案 6 :(得分:0)

这就是我做的。几乎没有内置插件:

split_list_in_half( Xs , H , T ) :-
  list_length( X , L ) ,
  LL = L - (L // 2) ,
  take_first( Xs , LL , H , T ) ,
  .

list_length( L , N ) :-
  list_length( L , 0 , N )
  .

list_length( [] , N , N ).
list_length( [X|Xs] , T , N ) :-
  T1 is T+1 ,
  list_length( Xs , T1 , N )
  .

take_first( Xs , N , Pfx , Sfx ) :-
  take_first( Xs , N , [] , P1 , Sfx ) ,
  reverse( P1 , Pfx )
  .

take_first( []     , _ , H  , H , []     ).
take_first( [X|Xs] , 0 , H  , H , [X|Xs] ).
take_first( [X|Xs] , N , H1 , H , T      ) :-
  N > 0    ,
  N1 = N-1 ,
  take_first( Xs , N1 , [X|H1] , H , T )
  .