Pablisky
Pablisky

Reputation: 55

How I can store the indexes where a number appears on a list of Prolog?

For example:
positions (X, L, R):- .

Where:

  1. X is the number that I am looking for.
  2. L is a list of many numbers.
  3. R is the list that will store the indexes where X appears

I got this, but it doesn´t "return" a list, it just gives me individual results:

pos(X,[X|_],0).
pos(,[],):- !,fail. pos(X,[_|R],Pos):- pos(X,R,Pos1), Pos is Pos1+1. 

Upvotes: 2

Views: 96

Answers (3)

user1812457
user1812457

Reputation:

If you have access to nth0/3 or nth1/3, it can be used to "find" the positions of an element in a list. For example:

?- List = [0,1,2,3,0,4,5,0], nth0(N, List, 0).
List = [0, 1, 2, 3, 0, 4, 5, 0],
N = 0 ;
N = 4 ;
N = 7.

All you need is to collect all answers in a list. Just use bagof/3:

?- List = [0,1,2,3,0,4,5,0], bagof(N, nth0(N, List, 0), Ns).
List = [0, 1, 2, 3, 0, 4, 5, 0],
Ns = [0, 4, 7].

You can define it as a predicate like this:

positions(X, L, R) :-
    bagof(N, nth0(N, L, X), R).

Unlike the other solutions, you can use this to find the positions of any element in the list upon backtracking:

?- positions(X, [0,1,2,0,2], R).
X = 0,
R = [0, 3] ;
X = 1,
R = [1] ;
X = 2,
R = [2, 4].

If you don't want to use nth0/3, just go ahead and use your own definition of pos/3, just make sure it does what it should. See for example the answer to the third of the 99 Prolog problems: it is a straight-forward implementation of nth1/3. You just have to change the 1 to 0 to get 0-based indices. It is almost identical to what you already had (as shown in your question).

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726699

You can modify your code like this:

positions(X, L, R) :- positions(X, L, R, 1).

positions(_, [], [], _).
positions(X, [X|T], [I|R], I) :- plus(I, 1, N), positions(X, T, R, N).
positions(X, [Y|T], R, I) :- X \= Y, plus(I, 1, N), positions(X, T, R, N).

Demo.

The positions/3 clause is there to add the current index I to positions/4 rule.

The three clauses of positions/4 are as follows:

  • The first, base, clause is for an empty list
  • The second clause is for matching the initial element to X
  • The third clause is to move on to the next element when there is no match (i.e. X \= Y).

Upvotes: 0

max66
max66

Reputation: 66210

I think you need a index and creare R accumulating the matching indexes.

By example

positionH(_, _, [], []).

positionH(I, X, [Y | Tl], Tr):-
  Y \= X, 
  Ip1 is I+1,
  positionH(Ip1, X, Tl, Tr).

positionH(I, X, [X | Tl], [I | Tr]):-
  Ip1 is I+1,
  positionH(Ip1, X, Tl, Tr).

position(X, L, R):-
  positionH(0, X, L, R).

Upvotes: 0

Related Questions