Split a list in half

后端 未结 7 1378
滥情空心
滥情空心 2020-12-19 03:25

I need to define divide so that List [1,2,3,4,5] divides into:

a = [1,2,3}

b = [4,5]

I\'m getting an error that says \"

相关标签:
7条回答
  • append is a pre-defined predicate, so that might be the issue: http://en.wikibooks.org/wiki/Prolog/Lists#The_append_predicate

    You also never defined 'N' in lengthIs - you need to set the empty list as 0, not N/ There's likely also a size function

    The underscore tells Prolog we don't care about that bit in that predicate definition.

    Something like this should work

    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).
    
    0 讨论(0)
  • 2020-12-19 03:53

    No need to check sizes. Just do it like this:

    div([],[],[]).
    div([A],[A],[]).
    div([A,B|T],[A|X],[B|Y]) :- div(T,X,Y).
    
    0 讨论(0)
  • 2020-12-19 04:02

    Let's give the predicate a more relational name: 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).
    

    length/2 and append/3 are predefined in practically all recent Prologs.

    This is 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]
    
    0 讨论(0)
  • 2020-12-19 04:05

    Another answer, uses Backtracking a lot, isn't very performant, though. append and length are assumed to be predefined:

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

    Oh, sorry, just have seen that this is sort of a rephrasing of the answer from Philip Whitehouse.

    0 讨论(0)
  • 2020-12-19 04:12

    This is how I did it. Almost no built-ins:

    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 )
      .
    
    0 讨论(0)
  • 2020-12-19 04:17

    This is the most efficient solution conforming to your specification for most Prolog implementations:

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

    If you don't mind which elements go into the sublists as far as they are of similar length (as in the solution from Konstantin Weitz post), then you can use :

    divide([], [], []).
    divide([H|T], [H|A], B) :- divide(T, B, A).
    
    0 讨论(0)
提交回复
热议问题