Search code examples
listprologpredicate

Implementation of predicate similar to Transpose in Prolog


I am pretty new to Prolog, actually 4 days into it and I came across an exercise that states :

Given a list of N lists with N size each implement a predicate called reshape(X,Y) so that it :

  • Collects the first elements of all lists into a list.
  • Collects the second elements of all lists lists into a list.
  • ...
  • Collects the N elements of all lists into a list.
  • Collects all lists mentioned above into a new list.

An example would be :

  • reshape([[1,2,3],[4,5,6],[7,8,9]],X)
  • X = [[1,4,7],[2,5,8],[3,6,9]]

So here is my implementation :

% Insert at the end of a list

insert([],X,[X]).
insert([H|T1],X,[H|T2]) :- insert(T1,X,T2).
% Length of list

len([],L,L).

len([_|T],L,X) :- 
    L1 is L + 1,
    len(T,L1,X).

len(L,X) :- len(L,0,X).
% Create a list of N empty lists

init_list(L,0,L) :- !.

init_list(L,N,X) :-
    N1 is N-1,
    insert(L,[],Y),
    init_list(Y,N1,X).

init_list(N,X) :- init_list([],N,X).
% Assign each element of a list to the corresponding list.

assign([],[],[]).
assign([H1|T1],[H2|T2],[Y|T3]) :- 
    insert(H2,H1,Y),
    assign(T1,T2,T3).
% Reshape :

reshape([],L,L).
reshape([H1|T1],X,Result):-
    assign(H1,X,Y),
    reshape(T1,Y,Result).    

reshape(Input,Result) :-
    len(Input,N), 
    init_list(N,X),
    reshape(Input,X,Result).    

So the basic idea is that I start by creating a list of N empty lists and then for each list say L of the input I assign/add each element of L to the corresponding list.

Now I would appreciate some input as I already said I am new to Prolog and can't even tell what the time complexity of my predicate is.The only thing I know for a fact is that it works.

Howerever is there a better way I can implement it?

What's the time complexity of my implementation ? It seems like polynomial time but I can't really tell.

Thanks in advance.


Solution

  • You can code an O(N) algorithm that just goes through each element once:

    reshape([[]|Tail], []):-
      maplist(=([]), Tail).
    reshape(Input, [Result|RTail]):-
      reshape(Input, LTail, Result),
      reshape(LTail, RTail).
      
    reshape([], [], []).
    reshape([[Item|Tail]|LTail], [Tail|MTail], [Item|RTail]):-
      reshape(LTail, MTail, RTail).
    

    reshape/3 gets the list with every first element of the list of lists. Then reshape/2 builds all such lists recursively.

    Test case:

    ?- reshape([[1,2,3],[4,5,6],[7,8,9]],X).
    X = [[1, 4, 7], [2, 5, 8], [3, 6, 9]] ;
    false.