Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find all positions of a value in a list in Prolog

Tags:

prolog

My assignment is this: Write a program that reads an integer x and a list of integers L; then locate the list of all positions of x into L, and return the resulting list. For example, for x=2 and L=[1,2,3,4,2,5,2,6] the program should return the list R=[2,5,7].

So far, I've been able to write an indexOf predicate:

indexOf([E|_], E, 1).
indexOf([_|T], E, I) :- indexOf(T, E, I2), I is I2 + 1.

However, this doesn't "return" a list. So:

indexOf([a,b,c,a,d], a, R).
R = 1;
R = 4

I'd like to do something like this:

findAll([a,b,c,a,d], a, R).
R = [1, 4]

But I'm not sure how to collect the values into a list.

This is a school assignment, so I'd appreciate just a nudge in the right direction.

like image 512
Andrew Burgess Avatar asked Jan 26 '26 18:01

Andrew Burgess


1 Answers

A nudge: you find the indices, but you don't collect them.

indices(List, E, Is) :-
    indices_1(List, E, Is, 1).

For an empty list, the list of indices is empty, and the element doesn't matter

indices_1([], _, [], _).

If the element is like the head, collect the index.

indices_1([E|Xs], E, [I|Is], I) :-
    I1 is I + 1,
    indices_1(Xs, E, Is, I1).

This needs another clause to work properly.

EDIT:

One way to do it would be:

indices_1([X|Xs], E, Is, I) :- dif(X, E),
    I1 is I + 1,
    indices_1(Xs, E, Is, I1).

In the previous clause, the head of the list and the Element are unified. In this clause, they are explicitly different. This means that only one of the two clauses can be true for an element of the list in the first arguemnt.

EDIT:

Another way to do that is to use findall and nth1:

indices(List, E, Is) :-
    findall(N, nth1(N, List, E), Is).