Extracting a column from a list of lines in Prolog

I am trying to extract a certain column(COLUMN) of index (K) from a list of lines (X).

This is the code I wrote so far:

extract(K,X,COLUMN):-
    constructColumn(K,1,X,COLUMN).


constructColumn(K,B,X,COLUMN):-
    nth1(B,X,LINE),
    nth1(K,LINE,ELEMENTCOLUMN),
    incr(B,B1),
    constructColumn(K,B1,X,ELEMENTCOLUMN|COLUMN);
    !.

incr(X, X1) :- X1 is X+1.

When I trace to see how it functions, I see that the new COLUMN list that I am building is not kept to give as an output at the end, it just outputs true. Is there a way for me to add elements to the predicate in a similar way?

Upvotes: 1

Views: 1292

Answers (3)

CapelliC
CapelliC

Reputation: 60034

Just to show the modification required to make your code working:

extract(K,X,COLUMN):-
    constructColumn(K,1,X,COLUMN).

constructColumn(K,B,X,[ELEMENTCOLUMN|COLUMN]):-
    nth1(B,X,LINE),
    nth1(K,LINE,ELEMENTCOLUMN),
    succ(B,B1),
    !,
    constructColumn(K,B1,X,COLUMN).
constructColumn(_K,_B,_X,[]).

Let's explain: we use nth1(B,X,LINE) to access every row, when it fails we're done. The first improvement could be to get rid of this access by index to rows: just let the list (of lists) control the recursion:

extract(_,[],[]).
extract(K,[LINE|LINES],[ELEMENTCOLUMN|COLUMN]):-
    nth1(K,LINE,ELEMENTCOLUMN),
    extract(K,LINES,COLUMN).

much better, isn't it ?

Upvotes: 0

lurker
lurker

Reputation: 58324

The maplist/3 predicate also works well here. maplist will apply a predicate to a set of list arguments resulting in other list arguments, where that predicate is designed to work on one argument.

So you can write extract/3 as:

extract(ColNumber, Matrix, Column) :-
    maplist(nth0(ColNumber), Matrix, Column).

And you're done. :)

| ?- extract(2, [[a,b,c,d],[e,f,g,h],[i,j,k,l]], R).

R = [c,g,k]

yes
| ?-

Upvotes: 3

coder
coder

Reputation: 12992

Since you have many iterations you could skip most of the writing by using findall/3 predicate:

extract(K,X,COLUMN):- findall(Elem , (member(X1,X), nth0(K,X1,Elem)) , COLUMN).

What the above does is for each X1 line (member of X lines) take the Kth element (using nth0/3 predicate) and store it to COLUMN list.

You can read about findall/3 here: www.swi-prolog.org/pldoc/man?predicate=findall/3

Example:

?- extract(1,[[1,2,3,4],[11,22,33,44],[111,222,333,444]],COLUMN).
COLUMN = [2, 22, 222].

?- extract(0,[[1,2,3,4],[11,22,33,44],[111,222,333,444]],COLUMN).
COLUMN = [1, 11, 111].

?- extract(2,[[1,2,3,4],[11,22,33,44],[111,222,333,444]],COLUMN).
COLUMN = [3, 33, 333].

?- extract(3,[[1,2,3,4],[11,22,33,44],[111,222,333,444]],COLUMN).
COLUMN = [4, 44, 444].

?- extract(5,[[1,2,3,4],[11,22,33,44],[111,222,333,444]],COLUMN).
COLUMN = [].

Upvotes: 0

Related Questions