Lucian Tarna
Lucian Tarna

Reputation: 1827

Replace a single occurrence of an element in a list in Prolog

I am given a list, an element to be replaced and the replacement for that element. I managed to do it for all occurrences of the element in that list:

replace([],X,Y,[]).
replace([X|T], X, Y, Z) :-
   replace(T, X, Y, Z1),
   Z = [Y|Z1].
replace([H|T], X, Y, [H|Z]) :-
   replace(T, X, Y, Z). 

However now I must only replace the first occurrence of that element. My thought process writing:

replace([X|T], X, Y, Z) :-
   replace(T, X, Y, Z1), 
   Z = [Y|Z1].

was:
Z is the result of [X|T],X,Y if Z1 is the result of T,XY and Z = [Y|Z1]. Following the same thought process I tried writing the function that only replaces the first occurrence of the element like so:

An idea for implementing only the first occurrence would be from a replace/4 to go in a replace/5 where I count if I replaced or not like so:

replace_single(L,X,Y,Z) :- 
   replace2(L,X,Y,0,Z).

replace2([],X,Y,C,[]).
replace2([X|T], X, Y, C, Z) :-
   \+ (C = 0),
   replace2(T, X, Y, C, Z1),
   Z = [X|Z1],
   C is 1.
replace2([H|T], X, Y, C, [H|Z]) :-
   replace2(T, X, Y, C, Z).

Obviously it will not work, I am a little bit lost. Could someone give me a tip or so of how I could think to solve the problem or the solution itself?

Upvotes: 2

Views: 2767

Answers (3)

Arushi
Arushi

Reputation: 85

Another way to do it will be:-

replace(E1,L1,E2,L2) :-
same_length(L1,L2),
append(BeforeElement,[E1|AfterElement],L1),
append(BeforeElement,[E2|AfterElement],L2).

where BeforeElement stands for prefix of the list before the element and After Element stands for suffix of the list after the element.

Upvotes: 0

lurker
lurker

Reputation: 58244

Another approach would be to use a DCG:

rep1(X, Y, [Z|T]) --> [Z], { dif(Z, X) }, rep1(X, Y, T).
rep1(X, Y, [Y|T]) --> [X], rest(T).
rep1(_, _, []) --> [].

rest([]) --> [].
rest([H|T]) --> [H], rest(T).

| ?- phrase(rep1(a, 1, L), [a,b,c,a,d]).

L = [1,b,c,a,d] ? ;

| ?- phrase(rep1(a, 1, [x, y, 1, b]), L).

L = [x,y,1,b] ? a

L = [x,y,a,b]

You can write your predicate as:

replace(X, Y, L, R) :- phrase(rep1(X, Y, R), L).

Upvotes: 1

repeat
repeat

Reputation: 18726

We define replace/4 based upon same_length/2, append/3, maplist/2, and :

replace(Xs,X,Y,Ys) :-
   same_length(Xs,Ys),
   append(Prefix,[X|Suffix],Xs),
   maplist(dif(X),Prefix),
   append(Prefix,[Y|Suffix],Ys).

Sample queries:

?- replace(Xs,2,two,[1,two,3,4,5,1,2,3,4,5,1,2]).
  Xs = [1,2,3,4,5,1,2,3,4,5,1,2]
; false.

?- replace([1,2,3,4,5,1,2,3,4,5,1,2],2,two,Ys).
  Ys = [1,two,3,4,5,1,2,3,4,5,1,2]
; false.

Upvotes: 1

Related Questions