I want to be able to split a list in two at a certain element. For example, split_at(c, [a,b,c,d,e], Left, Right) should give me Left = [a,b] and Right = [c,d,e]. At the moment, my code just gives me nothing at the end, even though I see Left and Right being built in the trace. Can someone please point out the mistake(s)?
split_at(_, [], [], []).
split_at(Element, [Element|T], _, [Element|T]).
split_at(Element,[H|T], Left, _) :- split_at(Element, T, [H|Left], _).
split_at(Elem,List,Left,Right) :-
append(Left,[Elem|Rest],List), Right = [Elem|Rest].
Assuming you mean split on the first occurrence of the specified element (and not on the 3rd item in the list) :
split_left_right_list(Split,[],[Split|Rest],[Split|Rest]).
split_left_right_list(S,LR,R,[First|Rest]):-
dif(First,S),
split_left_right_list_ac(S,L,R,Rest,[First]),
reverse(L,LR).
split_left_right_list_ac(_,AC,[],[],AC).
split_left_right_list_ac(S,AC,[S|Rest],[S|Rest],AC).
split_left_right_list_ac(S,L,R,[Not|Rest],AC):-
dif(Not,S),
split_left_right_list_ac(S,L,R,Rest,[Not|AC]).
Related
How do you make a rule that returns all elements besides the last in another list in Prolog using append? I've made the equivalent without append but I can't figure out the append solution
remlast([_],[]).
remlast([H1|T1],[H2|T2]):-
H2=H1,
remlast(T1,T2),
!.
I can get the last element from a list with append with this
mylastAppend(X,List):-
append(_,[X],List),!.
But I can't figure out how to use that in the above example
Use:
list_front(List, Front) :-
append(Front, [_], List).
This will split the list in Front of the list and a one-element list from the back of List.
Your "equivalent without append" is not optimal. This is better: https://stackoverflow.com/a/51291825/
Here is a variation which results in a difference list (which can then be used for e.g. an efficient append):
list_without_last_dl(Lst, LstWithout, LstWithoutTail) :-
Lst = [H|T],
list_without_last_dl_(T, H, LstWithout, LstWithoutTail).
list_without_last_dl_([], _H, W, W).
list_without_last_dl_([H|T], H2, [H2|W], WT) :-
list_without_last_dl_(T, H, W, WT).
Result in swi-prolog:
?- list_without_last_dl([a,b,c], W, WT).
W = [a,b|WT].
I'm trying to modify a list by search and replace, was wondering how do I search through a list with the search term as a list as well?
Lets say I have a list [1,2,3,4] I want to single out the 2 and 3 and replace it with 5,6
so ideally I could have a predicate:
search_and_replace(Search_Term, Replace_Term, Target_List, Result_List).
eg.
search_and_replace([2,3], [5,6], [1,2,3,4], Result_List), write(Result_List).
Let me assume that you want to replace a subsequence substring within a list by another list.
Here is a general way how to do this. You might want to insert
further conditions into the program.
replacement(A, B, Ag, Bg) :-
phrase((seq(S1),seq(A),seq(S2)), Ag),
phrase((seq(S1),seq(B),seq(S2)), Bg).
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
And, yes this can be optimized a bit - even its termination property
would profit. But conceptual clarity is a quite precious value...
Edit: Your example query:
?- replacement([2,3], [5,6], [1,2,3,4], Xs).
Xs = [1,5,6,4]
; false.
You can use append/2 as follows :
replace(ToReplace, ToInsert, List, Result) :-
once(append([Left, ToReplace, Right], List)),
append([Left, ToInsert, Right], Result).
With or without use of once/1 depending on if you want all the possibilies or not.
To replace all the occurences I'd go with something like :
replace(ToReplace, ToInsert, List, Result) :-
replace(ToReplace, ToInsert, List, [], Result).
replace(ToReplace, ToInsert, List, Acc, Result) :-
append([Left, ToReplace, Right], List),
append([Acc, Left, ToInsert], NewAcc),
!,
replace(ToReplace, ToInsert, Right, NewAcc, Result).
replace(_ToReplace, _ToInsert, [], Acc, Acc).
I am trying to get my head wrap around lists in Prolog. To do this I am trying to create a sort of game. You pass in a list of numbers 1-9 that can be repeated, the list can be any length. The rules are that starting from the first element(e) you can only move to e+2 or e+3 until you get to the end. The goal is to "land" on the highest numbers. In essence it is kind of like hopscotch. The problem I am running into is determining all the possible permutation for paths. So far I have the following.
paths([], []). %empty list returns empty list
paths([X], [X]). %list with one element returns that one element
paths([X1, X2], [X1]). %list with 2 elements returns the first element
paths([X1, X2, X3], [X1,X3]). %list with three elements returns the first and third element
paths() :- % the recursive case for a list with 4+ elements
An list to use would be: [1,2,3,4,5,6,8,7,9,3,6,5,7,8,9]
I need to determine all possible paths using the rule mentioned about. I wish lists could be indexed in Prolog :(
Any logic guidance would be appreciated.
The requirements aren't completely clear, but it seems that:
The second argument is required to have the same first element as the
first argument (you "hop" on the first "square" first always, using
your hopscotch metaphore)
You aren't requiring that the last element of the first list be the
last element of the second list (you aren't requiring that you "land
on" the last "square").
An empty list succeeds with an empty list result (rather than just failing on an empty list - which is another valid approach).
Then this could be implemented as follows. You do not need many explicit 2- and 3-element list cases since they are handled by the recursive clause and simpler base cases.
path([], []).
path([X], [X]).
path([X,_|T], [X|R]) :- % hop over 1 element
path(T, R).
path([X,_,_|T], [X|R]) :- % hop over 2 elements
path(T, R).
For a simple example:
| ?- path([1,2,3,4,5,6], R).
R = [1,3,5] ? ;
R = [1,3,6] ? ;
R = [1,4,6] ? ;
R = [1,4]
yes
If I don't have your requirements exactly right, you should be able to adjust this to suit your needs as it shows how to handle a recursive case. It also sounds like you are headed in the direction of trying to optimize the values in your hops, which I shall also leave as an exercise.
This can also be done with a DCG (definite clause grammar)
path([]) --> [].
path([X]) --> [X].
path([X|T]) --> ([X,_] | [X,_,_]), path(T).
Which would be exercised:
| ?- phrase(path(R), [1,2,3,4,5,6]).
R = [1,3,5] ? ;
R = [1,3,6] ? ;
R = [1,4,6] ? ;
R = [1,4] ? ;
(1 ms) no
| ?-
In light of the extra requirement that the last step taken must be one that falls within the list, here is an updated version of the path/2 predicate:
path([], []).
path([X], [X]).
path([X,_], [X]).
path([X,_,Y|T], [X|R]) :- % hop over 1 element
path([Y|T], R).
path([X,_,_,Y|T], [X|R]) :- % hop over 2 elements
path([Y|T], R).
I think that there is a reason to avoid indexing: simplicity. If you decompose your problem, maybe you could start writing a step/3 predicate like
step([_,X|T],X,T).
step([_,_,X|T],X,T).
and then
paths([],[]).
paths(L,[X|Xs]) :- step(L,X,T), paths(T,Xs).
note: I don't understand very well your game, some example of playground and solution would be welcome.
%passing in a list and return all possible paths using K+2 or K+3 with K being the first element of the list.
%empty list returns empty list
%list with one element returns that one element
%list with 2 elements returns the first element
%list with three elements returns the first and third element
%list with four/four+ elements needs to be called recursively, prefix them with the first element and append them together
%RL means ReturnList
%FL means FinalList
%List is the appended list containing all the paths
paths([], []).
paths([X], [[X]]).
paths([X1, X2], [[X1]]).
paths([X1, X2, X3], [[X1,X3]]).
paths([X1, X2, X3, X4 | T], List) :-
paths([X3,X4|T], RL), paths([X4|T], RL2),
prefix_all(X1, RL, FL1), prefix_all(X1, RL2, FL2),
append(FL1, FL2, List).
So if run with the list [1,2,3,4,5] is would produce the following:
| ?- paths([1,2,3,4,5],X).
X = [[1,3,5],[1,4]] ? ;
no
I have a list, let's say X=[a,b,c,d,c,e,d], how can I delete one of each character so the only answer remains X1=[c,d].
I have a bunch of lists with just alphabetical letters and I need a command which would delete every single letter once if list contains such and do nothing if there's none of that letter.
I have tried using selectchk/3 for this but it only works for specific cases.
For instance if I have list X=[a,b,c,d,d,e,e,f,f,g,h],
I can write selectchk(d,X,X1), selectchk(e,X1,X2), selectchk(f,X2,X3) etc.
As I said, this only works for specific case, however if I add general predicate, let's say I have selectchk/3 for every single letter, but, for example,
new list is X1=[a,b,c,d,d] and I use selectchk(f,X,X3),
command fails and doesn't name the next list X3, so the next command which checks for letter 'G' in list X3 can't run since there's no such list. Is there a possibility to do OR command, if one fails?
X=[a,a,c,d,d,e]
selectchk(a,X,X1) OR (if there's no a) append([],X,X1),selectchk(b,X1,X2) OR (if there's no 'b'), append([],X2,X3) etc.
Thanks
There are several ways one could do this. I think selectchk/3 forms a good basis for a solution, which is really to "automate" what you attempted to do manually and use a recursion:
select_each_one(L, R) :-
sort(L, PickList),
select_each_one(L, PickList, R).
select_each_one(L, [H|T], R) :-
selectchk(H, L, R1),
select_each_one(R1, T, R).
select_each_one(L, [], L).
The sort provides a "picklist" containing just one of each of the elements in the original list. The select_each_one/3 predicate then performs the selectchk with each of those elements on each iteration of the original list.
?- select_each_one([a,b,c,d,c,e,d], L).
L = [c, d] ;
false.
?- select_each_one([a,b,c,d,d,e,e,f,f,g,h], L).
L = [d, e, f] ;
false.
Another approach would be to copy the list over one element at a time, but track whether we've seen the element or not:
select_each_one(L, R) :-
select_each_one(L, [], R).
select_each_one([H|T], Seen, R) :-
( member(H, Seen)
-> R = [H|R1], select_each_one(T, Seen, R1)
; select_each_one(T, [H|Seen], R)
).
select_each_one([], _, []).
a List of Lists like
Lists=[ [1,2,3],
[4,5,6],
[7,8,3] ]
and i want to get in this case all vertical lists like
[1,4,7], [2,5,8], [3,6,3]
how to do that? i thought about 2 counters witch work together like two "for to do" repeats.
i need to check with "is_set" if [1,4,7] is a set or [3,6,3] witch of course is not.
like this:
el_at(Llist,Gl,1),
el_at(EList, Llist,1),
globalListVertikalCheck(ListVertikal),
addlist(Elist,ListVertikal,NewListVertikal),
el_at(Llist,Gl,2),
el_at(EList, Llist,2),
globalListVertikalCheck(ListVertikal),
addlist(Elist,ListVertikal,NewListVertikal),
thanks
A list of all vertical lists is known as a transposed matrix.
SWI's library(clpfd) contains such code.
I didn't fully understand the solution you propose, but I have another one. I will try to describe how it works and maybe than you can see what was wrong with your solution and why it didn't work.
Let's consider an example of [[1,2], [3,4]]. The idea is to go through the first sub-list [1,2] and create an incomplete result [[1],[2]], then go through the next one [3,4] and prepend (which is easier than append in Prolog) each item in it to the each sub-list in the result. We will end up with [[3,1], [4,1]]. The sub-lists are then reversed and we have the result [[1,3],[1,4]].
Now the implementation:
The vertical predicate is the core, it goes through the list of lists and the result is step by step accumulated in the Acc varible.
For each of the sublists, the vertical predicate calls the addfirst predicate, which takes each element of that sublist and prepends it to the list in which the previous results were accumulated.
vertical([X|Xs],Result):-
createempty(X, Acc),
vertical([X|Xs], Acc, ReversedResults),
reverseall(ReversedResults, Result).
reverseall([], []).
reverseall([X|Xs], [XReversed|Rest]):-
reverse(X, XReversed),
reverseall(Xs, Rest).
createempty([], []).
createempty([X|Xs], [[]|R]):-createempty(Xs,R).
vertical([], Result, Result).
vertical([X|Xs], Acc, Result):-
addfirst(X, Acc2, Acc),
vertical(Xs, Acc2, Result).
addfirst([], [], []).
addfirst(
[Y|Ys],
[[Y|YVerticalRest]|ResultRest],
[YVerticalRest|VerticalsRest]):-
addfirst(Ys, ResultRest, VerticalsRest).
Here goes a small implementation of transpose:
It works by taking the first element of every sublist. When it finishes, it recursively does the same but now with the next item of each list, and so on.
transpose(M, T):-
transpose(M, [], T).
transpose([], [], []).
transpose([], S, [[]|T]):-
S \= [] ->
(reverse(S, M), transpose(M, [], T)).
transpose([[]|MTail], S, T):-
transpose(MTail, S, T).
transpose([[Item|Tail]|MTail], S, [[Item|NTail]|T]):-
transpose(MTail, [Tail|S], [NTail|T]).
transpose([[]|_],[]) :- !.
transpose(L,[L1|R2]) :-
transpose(L,L2,L1),
transpose(L2,R2).
transpose([],[],[]) :- !.
transpose([[A|R1]|R2],[R1|R3],[A|R4]) :-
transpose(R2,R3,R4).