Replace elements of a list with Prolog - prolog

how to replace any of the element in the list with prolog?
example:
replace(2,[1,2,3,2,1],5,X)
should have both the solutions:
X = [1,5,3,2,1]
X = [1,2,3,5,1]

You can do it by iterating over the input list:
%replace(_, [], _, []).
replace(Element, [Element|Tail], NElement, [NElement|Tail]).
replace(Element, [CurElement|Tail], NElement, [CurElement|NTail]):-
replace(Element, Tail, NElement, NTail).
Sample input:
?- replace(2,[1,2,3,2,1],5,X).
X = [1, 5, 3, 2, 1] ;
X = [1, 2, 3, 5, 1] ;
If you uncomment the first clause it would also output the solution where the output list remains unchanged.
The first clause (commented) is a base case for iterating over a list. It states that the replaced list of an empty list is the empty itself.
The second clause states that if the head of the list unifies with the Element then the replace list would contain the replaced element and the rest of the list (Tail).
The third clause is the recursive step, it takes the first element and calls recursively with the tail of the list, and the output is the element taken concatenated with the result of the recursive call.

Related

forming successive list of numbers in Prolog [duplicate]

I am trying to keep only the first element and the last element for a list which contains only consecutive integers.
For example:
?- remove([1,2,3,4,5], NewList).
NewList = [1,5].
I can only successfully keep the last element:
remove([], []).
% for consecutive integers in the list
remove([ Head | Tail ], NewList) :-
check_consecutive(Head, Tail),
remove(Tail, NewList).
% for the case when the list is empty
remove([ Head | Tail ], [ Head | NewList ]) :-
not(check_consecutive(Head, Tail)),
remove(Tail, NewList).
check_consecutive(Num, [ Head | _ ]) :-
Num is Head - 1.
I have been tying to keep the first element, but it keeps giving me the last element.
If there are some elements which is not consecutive, it should do some thing like:
?- remove([1,2,4,5,6,8,3], NewList).
NewList = [[1,6], 8, 3].
Any assistance is appreciated.
To solve this problem you have to handle different cases, here the solution then the comment:
last([E],E).
last([_|T],E):-
last(T,E).
remove([],[]).
remove([A],[A]).
remove([A,B],[A,B]).
remove([A|B],[A,Last]):-
last(B,Last).
findElementsR([A,B],LT,LOT,LO):-
B =< A,
append(LT,[A],LT1),
remove(LT1,LRem),
append(LOT,[LRem,[B]],LO).
findElementsR([A,B|T],LT,LOT,LO):-
B =< A,
append(LT,[A],LT1),
remove(LT1,LRem),
append(LOT,[LRem],LOT1),
findElementsR([B|T],[],LOT1,LO).
findElementsR([A,B],LT,LOT,LO):-
B is A+1, %consecutive
append(LT,[A,B],LTO),
remove(LTO,RM),
append(LOT,[RM],LO).
findElementsR([A,B|T],LT,LOT,LO):-
B is A+1, %consecutive
append(LT,[A],LTO),
findElementsR([B|T],LTO,LOT,LO).
findElements(L,LO):-
findElementsR(L,[],[],LO).
?- findElements([3,1,2,3,2,3,4,5,2,3,4],L).
L = [[3], [1, 3], [2, 5], [2, 4]]
false
So, first of all, i've defined last/2 that simply, given a list as an input, returns the last element
?- last([1,2,3],L).
L = 3
Then with remove/3 i get the list composd by th first and the last element.
findElements/2 is used to call findElementsR/4 (to make it tail recursive). findElements/4 finds a list of consecutive elements and then calls remove/2 to get the first and the last.

Prolog Remove the elements between the first and the last elements in a list

I am trying to keep only the first element and the last element for a list which contains only consecutive integers.
For example:
?- remove([1,2,3,4,5], NewList).
NewList = [1,5].
I can only successfully keep the last element:
remove([], []).
% for consecutive integers in the list
remove([ Head | Tail ], NewList) :-
check_consecutive(Head, Tail),
remove(Tail, NewList).
% for the case when the list is empty
remove([ Head | Tail ], [ Head | NewList ]) :-
not(check_consecutive(Head, Tail)),
remove(Tail, NewList).
check_consecutive(Num, [ Head | _ ]) :-
Num is Head - 1.
I have been tying to keep the first element, but it keeps giving me the last element.
If there are some elements which is not consecutive, it should do some thing like:
?- remove([1,2,4,5,6,8,3], NewList).
NewList = [[1,6], 8, 3].
Any assistance is appreciated.
To solve this problem you have to handle different cases, here the solution then the comment:
last([E],E).
last([_|T],E):-
last(T,E).
remove([],[]).
remove([A],[A]).
remove([A,B],[A,B]).
remove([A|B],[A,Last]):-
last(B,Last).
findElementsR([A,B],LT,LOT,LO):-
B =< A,
append(LT,[A],LT1),
remove(LT1,LRem),
append(LOT,[LRem,[B]],LO).
findElementsR([A,B|T],LT,LOT,LO):-
B =< A,
append(LT,[A],LT1),
remove(LT1,LRem),
append(LOT,[LRem],LOT1),
findElementsR([B|T],[],LOT1,LO).
findElementsR([A,B],LT,LOT,LO):-
B is A+1, %consecutive
append(LT,[A,B],LTO),
remove(LTO,RM),
append(LOT,[RM],LO).
findElementsR([A,B|T],LT,LOT,LO):-
B is A+1, %consecutive
append(LT,[A],LTO),
findElementsR([B|T],LTO,LOT,LO).
findElements(L,LO):-
findElementsR(L,[],[],LO).
?- findElements([3,1,2,3,2,3,4,5,2,3,4],L).
L = [[3], [1, 3], [2, 5], [2, 4]]
false
So, first of all, i've defined last/2 that simply, given a list as an input, returns the last element
?- last([1,2,3],L).
L = 3
Then with remove/3 i get the list composd by th first and the last element.
findElements/2 is used to call findElementsR/4 (to make it tail recursive). findElements/4 finds a list of consecutive elements and then calls remove/2 to get the first and the last.

How prolog deals with this step-by-step?

I'm trying to understand prolog but I am stuck with one example, can you explain to me how is prolog going through this call:
eli(2,[2,2,1],L).
using those facts:
eli(X,[],[]).
eli(X,[Y],[Y]).
eli(X,[X,X|L],L1) :- eli(X,L,L1).
eli(X,[Y|L],[Y|L1]) :- eli(X,L,L1).
The results are:
L = [1]
L = [1]
L = [2, 2, 1]
L = [2, 2, 1]
and I'm not really sure why.
Thanks in advance!
It looks like your predicate is mean to delete two consecutive appearance of any element.
First clause, if the target list is empty, return the empty list. In this case the X variable in the fact is not necessary. Replace X by te anonymous variable.
eli(_,[],[]).
Second clause is similar to the first, but it matches the target list if it contains only one element. Variable X is also not necessary.
eli(_,[Y],[Y]).
Third clause, if the target list contains two or more elements, and in the Head of the list both elements are equal to X, don't copy this two elements to the Result list, and make a recursive call to the eli/3 predicate in the body of the rule, to continue the search.
eli(X,[X,X|L],L1) :- eli(X,L,L1), !.
In this case we add the cut predicate, to avoid backtracking after this rule succeeded. Otherwise you may get undesired results, like L = [2, 2, 1] in your test.
And the last clause, copy the element in the Head of the Target list to the Result list, and continue the recursive call, this will stop when the Target list is empty or contains only one element (your first two clauses).
eli(X,[Y|L],[Y|L1]) :- eli(X,L,L1).
Now this is your predicate eli/3:
eli(_,[],[]).
eli(_,[Y],[Y]).
eli(X,[X,X|L],L1) :- eli(X,L,L1), !.
eli(X,[Y|L],[Y|L1]) :- eli(X,L,L1).
Test:
?- eli(2,[2,2,1],L).
L = [1]
?- eli(2,[1,2,2,3],L).
L = [1, 3]

Return the third to last elements of given list in Prolog

I am new in using Prolog, I want to write a program that compute the third to last element of a given list.
for instance
ThirdLast ([1, 2, 3, 4, 5] , Ans).
will give me:
Ans = [3, 4, 5]
I did this but is not working
len([],0).
len([_|T],N) :- len(T,X), N is X+1.
ThirdLast([ ],0)
ThirdLast([H|L1], X):-(len(L1,N)==2), X is H.
ThirdLast ([H|L1],X):-(len(L1,N)>2),ThirdLast (L1,X).
any ideas?
You can do it with a simple rule that ignores the first two elements:
tail3([_,_|T], T).
The first two elements get unified with _, and get thrown away. The rest of the list unifies with T, which is the result that we want to produce.
Demo.

Find a element in a sublist from a list at prolog

I have this
initialstate(0,[],[[1,0],[2,3],[1,2],[2,3]]).
I would like to find which sublist inside the list is the same with the number 1.
And after delete the sublist who had the number one.
It would be something like that :
?- initialstate(_,_,[X,_]), initialstate(_,_,list),
delete(list,X,Newlist),assertz(initialstate(A,B,Newlist)).
I know this is wrong but i am trying to explain you what i want to do.
I want my final list to be :
initialstate(0,[],[[2,3],[2,3]]).
Edit: A new answer to incorporate CapelliC's endorsement of delete/3 and OPs further queries in the comments.
Predicate:
initial_state_without_elements(initialstate(A,B,List), Element,
initialstate(A,B,FilteredList) ):-
delete(List, Element, FilteredList).
Query:
?- initial_state_without_elements(initialstate(0,[],[[1,0],[2,3],[1,2],[2,3]]), [2,_], NewState).
NewState = initialstate(0, [], [[1, 0], [1, 2]]).
We want to take some list of lists, ListOfLists, and remove all the sublists, Ls, that contain a given Element. In general, to check if an element X is in some list List, we we can use member(X, List).
So we want a list of lists, SubListsWithout, which contains all Ls of ListOfLists for which member(Element, SubList) is false.
Here is a predicate sublists_without_elements/3, which takes a list of lists, an element, and a variable as arguments, and unifies the variable with a list of the sublists of the first which do not contain the element. This predicate uses the standard recursive technique for describing lists:
sublists_without_element([], _, []).
sublists_without_element([L|Ls], Element, SubListsWithout) :-
member(Element, L), !,
sublists_without_element(Ls, Element, SubListsWithout).
sublists_without_element([L|Ls], Element, [L|SubListsWithout]) :-
sublists_without_element(Ls, Element, SubListsWithout).
The first clause is our base case: the empty list has no sublists, regardless of the element.
The second clause is true if (1) Element is a member of L, and (2) SubListsWithout is a list of the sublists of Ls which do not contain Element. (note: *L has not been added to SubListsWithout in this clause, which means it has been excluded from the lits we are accumulating. The ! is used to prune the search path here, because once we know that an Element is a member of L, we don't want to have anything to do with L again.)
The third clause is true if L is added to SubListsWithout, and SubListsWithout contains the rest of the sublists of Ls which do not have Element as a member.
The above is one way to write your own predicate to filter a list. It is important that you be able to write and read predicates of this form, because you will see tons of them. However, you'll also want to get to know the standard libraries of your Prolog implementation. In SWI-Prolg, you can simply use exclude\3 to accomplish the above task. Thus, you could achieve your desired goal in with the following:
filter_initial_state(initial_state(A,B,List),
Element,
initial_state(A,B,FilteredList)) :-
exclude(member(Element), List, FilteredList).
You can use it thus,
?- filter_initial_state(initial_state(0,[],[[1,0],[2,3],[1,2],[2,3]]), 1, Filtered).
and prolog will reply,
Filtered = initial_state(0, [], [[2, 3], [2, 3]]).
I think you've chosen the right builtin (delete/3), but there is some detail wrong. Here is a working 'query':
?- retract(initialstate(A,B,C)), C=[[X,_]|_], delete(C,[X,_],Newlist), assertz(initialstate(A,B,Newlist)).
A = 0,
B = [],
C = [[1, 0], [2, 3], [1, 2], [2, 3]],
X = 1,
Newlist = [[2, 3], [2, 3]].
First of all: if you do a assertz without first doing a retract you'll end with having an almost duplicate of your data, and probably is not what you want. assertz stores the updated initialstate after the old one (there is asserta, but I doubt will correct the bug).
Second, note how to use pattern matching to extract the essential information:
C=[[X,_]|_]
the use of _ (i.e. an anonymous var) is essential, because allows to specify which part of the complex structure we must ignore when using it. And we must use it also to indicate to delete/3 what to match.
delete(C,[X,_],Newlist)

Resources