Move elements between lists by index number? - list
I'm trying to move elements between Lists in LoL (list-of-list) structure.
I can figure out how to select the list and move the elements, but I'm lost on how to reconstruct the resulting LoL back.
Here is partial function :
move(From, To, State=[P1,P2,P3], NewState=[NP1, NP2, NP3]) :-
nth1(From, State, FL), nth1(To, State, TL), move_elem(FL, TL, NewFL, NewTL),
.....whats here?...
.. NewState should be build out of NewTL,NewFL and one of P1,P2,P3...
.. the order of the lists should be preserved..
move_elem/4 is implemented. From & To are integers and specify the lists-at-position that will participate in the move op.
Currently LoL is list of 3 lists, but I would like it in the future to parametrize the number of lists.
State is LoL before the move, NewState is the LoL after the move.
?- move_elem([1,2,3], [4,5,6], F,T).
F = [2, 3],
T = [1, 4, 5, 6].
nth1/3 seems to be working OK.
?- L=[[1,2],[3,4],[5,6]], nth1(2,L,El).
L = [[1, 2], [3, 4], [5, 6]],
El = [3, 4].
move() shold move element from one of the three lists to another.
From and To are the index-of-the-lists f.e.
LoL = [[1,2],[3,4],[5,6]]
move(1,3, LoL, NewLoL)
NewLoL = [[2],[3,4],[1,5,6]]
move(2,1, LoL, NewLoL)
NewLoL = [[3,1,2],[4],[1,5,6]]
move the top element from list-1 to list-3.
Using length/2 and append/3:
move(From, To, State, NewState):-
length([_|HState], From),
length([_|HNewState], To),
append(HState, [[Item|L]|TState], State),
append(HState, [L|TState], MState),
append(HNewState, [NL|TNewState], MState),
append(HNewState, [[Item|NL]|TNewState], NewState).
The idea is to use length/2 to produce a list on uninstantiated variables of length From-1 and another of length To-1 (thus we skip one element from the lists of length From and To).
Then append/3 can be used to split State in two parts or to concatenate two lists.
The first call to append will split State in a list HState of From-1 elements, and a second list with the rest. The first element from the rest is further split in two parts (the item to move and the rest of that element).
The second call to append joins the two parts excluding the item to be moved.
The third and fourth calls to append repeat this idea though this time they are used to add the moved item to the target location.
You can implement move/4 in this way:
appendHead(T,H,[H|T]).
removeHead([_|T],T).
insert(_,_,_,_,_,[],[]).
insert(C,I2,L1,L2,C,[_|TI],[L1|TO]):-
C1 is C+1,
insert(C,I2,L1,L2,C1,TI,TO).
insert(I1,C,L1,L2,C,[_|TI],[L2|TO]):-
C1 is C+1,
insert(I1,C,L1,L2,C1,TI,TO).
insert(I1,I2,L1,L2,C,[HI|TI],[HI|TO]):-
I1 \= C,
I2 \= C,
C1 is C+1,
insert(I1,I2,L1,L2,C1,TI,TO).
move(I1,I2,LIn,LOut):-
nth1(I1,LIn,L1),
nth1(I2,LIn,L2),
nth1(1,L1,E1),
removeHead(L1,L1R),
appendHead(L2,E1,L2F),
insert(I1,I2,L1R,L2F,1,LIn,LOut).
?- LoL = [[1,2],[3,4],[5,6]], move(1,3, LoL, NewLoL).
LoL = [[1, 2], [3, 4], [5, 6]],
NewLoL = [[2], [3, 4], [1, 5, 6]].
false.
?- LoL = [[2], [3, 4], [1, 5, 6]], move(2,1, LoL, NewLoL).
LoL = [[2], [3, 4], [1, 5, 6]],
NewLoL = [[3, 2], [4], [1, 5, 6]].
false.
?- LoL = [[1,2],[3,4],[5,6]], move(2,1, LoL, NewLoL).
NewLoL = [[3,1,2],[4],[1,5,6]].
false.
If you want to prevent backtracking, just add a cut ! after each definition of insert/4 (you will not get false).
Prolog does a depth-first search, meaning it will try to reach a goal by exploring all possible paths to a solution. Every time there are multiple paths available, it creates a choice point and then works its way down through the choices top to bottom. That means, if a choice immediately fails, the next will be called. This allows you to create the paths very clearly and you can give it choices to make. All atoms including lists are effectively immutable in Prolog. What you want to do is construct a second list from the first, possibly in a different order or with less elements, more elements, replaced elements etc.
I'm using replacement of a cell in a row with a cell(point(X,Y),Value) coordinate in a matrix as an example here. The three choices for rebuilding a list.
End of the list has been reached, this is the end condition and ends the new list.
The first cell of the list is checked and the coordinate doesn't match the replacement, so it's placed as is in the new list.
The first cell of the list does match the coordinate so place the element in the new list and close it off by adding the remaining unchecked elements as the tail.
This results in the code:
%coordinate not found, return the list as is
replace_cell(_,_,[],[]).
%no match, X already extracted from Element to reduce calls
replace_cell(X, Element, [RowElement|Tail], [RowElement|NewTail]) :-
RowElement \= cell(point(X,_),_),
replace_cell(X, Element, Tail, NewTail).
%match
replace_cell(X, Element, [cell(point(X,_),_)|Tail], [Element|Tail]).
This is the standard recursion you're probably used to. A goal is set, an answer is reached and Prolog starts stepping back through the calls made, filling in the variables we left open as it steps back. Then those filled variables become the output to the next returned call.
To then do it with multiple layers of lists, we just need to figure out which list we need to pass to the next, more specific call. In this matrix example, it's a square so all columns share an X and all rows share an Y coordinate. To figure out which row we need, we can feed the entire matrix into a simple predicate which checks the Y. Note that we aren't actually modifying the matrix yet, just identifying the row. This is mostly to keep the code readable.
%are there any rows left?
move_to_row(_, [], []).
%is element's Y equal to row Y?
move_to_row(Y, [Row|_], Row) :- Row = [cell(point(_,Y),_)|_].
%move to next row
move_to_row(Y,[_|Tail], Row) :- move_to_row(Y,Tail,Row).
After replacing the element in the row, since we have both the old and the new row we can identify the old row and reconstruct the matrix with the new row.
replaceElement(_,_,[],[]).
replaceElement(Replacable, Replacement, [Item|List], [Replacable|NewList] ) :-
Item \= Replacable,
replaceElement(Replacable, Replacement, List, NewList),
replaceElement(Replacable, Replacement, [Replacable|List], [Replacement|List] ) :-
!.
So effectively, the position in the list is kept by the order in which we step through the list on the way down, and then the new list is rebuilt on the way up.
For list [1,2,3], [Head|Tail] gives us Head = 1, Tail = [2,3]. If we then call [Head|Tail] again, it gives us Head = 2, Tail = [3]. On the way back, the exact opposite happens and the Head is appended to the front of the Tail. By visualizing each layer of lists as its own identifiable type and giving them their own identifier, it should be fairly simple to go through them efficiently irregardless of how many lists within lists you want to nest. The matrix is a 2d rectangle, but for example by having the coordinates within cell as a list and adding a Z axis it can fairly easily be turned into a cube or something even more complex with more than 3 dimensions.
Related
Most common sublist in Prolog
The problem is as follows: Write a predicate in Prolog most_common_sublist(L1,N,L2) that will find the sublist L2 with length N such that it is the most common sublist in L1. //Example 1: ?- most_common_sublist([1,2,2,3,2,2,4,2,2,3],1,L). L=[2]; //Example 2: ?- most_common_sublist([1,2,2,3,2,2,4,2,2,3],2,L). L=[2,2]; //Example 3: ?- most_common_sublist([1,2,2,3,2,2,4,2,2,3],3,L). L=[2,2,3]; My approach was to generate all the possible sublists of size N using the generator predicate, check which of those is the most common one in the list using the check predicate, and then just put that as my result. The reason why I'm not using the built-in predicates for length and add is because I'm supposed to write my own. My generator predicate works, it gives out the correct output. ?- generator([1,2,2,3,2,2,4,2,2,3],3,L). L = [[1, 2, 2], [2, 2, 3], [2, 3, 2], [3, 2, 2], [2, 2, 4], [2, 4, 2], [4, 2|...], [2|...]] [write] L = [[1, 2, 2], [2, 2, 3], [2, 3, 2], [3, 2, 2], [2, 2, 4], [2, 4, 2], [4, 2, 2], [2, 2, 3]] I checked all my predicates and they all seem to work (at least for the test cases I'm using), the problem occurs with the check predicate. It seems to work fine until it gets to N>=P (when this is NOT true, works fine when it is true). I expect the program to go onto the next check predicate under it (the third check predicate) so that it stores Temp value in Result instead of the H value. For some reason it does not go to the third check predicate (I checked with debugger), instead it does something weird (I can't figure out what). most_common_sublist(L,N,Result):-generator(L,N,LOP),check(LOP,_,Temp),add(Temp,[],Result). add([],L,L). add([X|L1],L2,[X|L3]):-add(L1,L2,L3). length([],0). length([X|O],N):-length(O,M),N is M+1. sublist([H|_],1,[H]). sublist([H|T],N,[H|LOP]):-M is N-1,sublist(T,M,LOP). generator(L,N,[L]):-length(L,M),N=:=M. generator([H|T],N,LOP):-sublist([H|T],N,PN),generator(T,N,LP),add([PN],LP,LOP). check([],Z,K):-Z is 0,add([],[],K). check([H|T],Hits,Result):-check_how_many(H,[H|T],N),check(T,P,_),N>=P,Hits is N,add(H,[],Result). check([H|T],Hits,Result):-check_how_many(H,[H|T],N),check(T,P,Temp),Hits is P,add(Temp,[],Result). check_how_many(X,[X],1). check_how_many(_,[_],0). check_how_many(Pattern,[H|T],Hits):-same(Pattern,H),check_how_many(Pattern,T,P),Hits is P+1. check_how_many(Pattern,[_|T],Hits):-check_how_many(Pattern,T,P),Hits is P. same([], []). same([H1|R1], [H2|R2]):- H1 = H2, same(R1, R2).
Since I'm not familiar with your code I rewrote it with similar functionality. Lines followed by %here are my improvements (2 times used). For simplicity I used the inbuild predicates length/2 and append/3 instead of add/3. sublist/3 has a complete different code but same functionality, same/2 is not necessary at all. Most uses of you add/3 were not necessary as well as some equality statements. most_common_sublist(L,N,Temp):- generator(L,N,LOP), check(LOP,_,Temp). sublist(L,N,S):- length(S,N), append(S,_,L). generator(L,N,[L]):- length(L,N). generator([H|T],N,LOP):- sublist([H|T],N,PN), generator(T,N,LP), append([PN],LP,LOP). check([],0,[]). check([H|T],N,H):- check_how_many(H,[H|T],N), check(T,P,_), N>=P. check([H|T],P,Temp):- check_how_many(H,[H|T],N), check(T,P,Temp) %here , N=<P . check_how_many(X,[X],1). check_how_many(_,[_],0). check_how_many(H,[H|T],Hits):- check_how_many(H,T,P), Hits is P+1. check_how_many(Pattern,[H|T],P):- %here Pattern \== H, check_how_many(Pattern,T,P). After giving up on tracing I just used the following call to debug after enabling long output ( ?- set_prolog_flag(answer_write_options,[max_depth(100)]). ): ?- findall(Temp,check([[1, 2, 2], [2, 2, 1]],_,Temp),Out). Initial output was Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[2,2,1],[2,2,1],[],[],[2,2,1],[2,2,1],[],[]]. Which contains way to much empty lists. First fix (%here) was to set the condition N=<P for the last check/3 case. Until now it was possible to choose a P lower than N, which should be covered by the 2nd check/3 case. Output changed to Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[2,2,1],[2,2,1],[2,2,1],[]]. Better, but still empty lists possible. A similar case happens in the last check_how_many/3 case: you have to state that H and Pattern are different, otherwise it would be possible for a fitting Pattern not to be counted. Lets check the output Out = [[1,2,2],[1,2,2],[1,2,2],[2,2,1]]. Way better. Lets check another case: ?- findall(Temp,check([[1, 2, 2], [1, 2, 2], [2, 2, 1]],_,Temp),Out). Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2]]. ?- findall(Temp,check([[1, 2, 2], [2, 2, 2], [1, 2, 2]],_,Temp),Out). Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[2,2,2],[2,2,2],[2,2,2],[1,2,2]]. Works... Almost. So the problem seems to be check_how_many/3: alter check_how_many(_,[_],0). to check_how_many(_,[],0). and you should be fine. ?- findall(Temp,check([[1, 2, 2], [2, 2, 2], [1, 2, 2]],_,Temp),Out). Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2]]. Since it is way more fun to write the code yourself than to debug foreign code I'll add another answer with my attempt.
It is way more fun to code by yourself than to debug alien code. So here is my attempt. It works different than yours because I do not calculate possible subsets but work on the "leftover" list. I use the inbuild predicates length/2, append/3 and member/2 which are 3 lines each to write down. % check how often 2.nd attribute List occurs in 1st attribute List. countit([],_,Val,Val). countit([H|In],Out,Past,Future):- ( append(Out,_,[H|In]) -> Present is Past+1, countit(In,Out,Present,Future) ; countit(In,Out,Past,Future) ). mostCommonSublist(In,N,Out):- maxStartList(In,N,OutList,Max), member((Max,Out),OutList). % for every endlist calculate how often the first N elements appear within the endlist, track the max maxStartList(In,N,[(1,In)],1):- length(In,N), !. maxStartList([H|In],N,[(CntH,Curr)|MaxList],Max):- length(Curr,N), countit([H|In],Curr,0,CntH), maxStartList(In,N,MaxList,CntIn), Max is max(CntH , CntIn). The main predicate mostCommonSublist/3 calls the predicate maxStartList/4 to get all sublists/countpairs. Afterwards it validates if the count of a sublist equals the maximum. This is neccessary to check for different answers with the same (maximum) count. The maxStartList/4 drops elements from the inputlist and counts how often the start of the current list occurs within it. Also it keeps track of the maximum. For the current inputlist the calculating predicate countit/4 is called. It calculated for a given inputlist (first argument) the number of occurences of a sublist (2nd argument). My code actually uses a twist: The content of the sublist is not unified when calling countit/4 for the first time, just the sublist length is set. In the first recursion it will unify all entries with the start elements from the inputlist and count it. In the following recursion steps the sublist if fully known. Using an if-then-else (..->..;..) the two cases for remaining inputlist starts with the sublist or not, the predicate basically counts the occurences. Until the remaining inputlist has only N elements left (length(In,N)). The calculated count/sublist pairs are stored in a list, the maximum is tracked as well. After knowing all count/sublist pairs I finallize it all by stating that the count of an accepted sublist has to be equal to the maximum. The nice thing is that there are no dublicate answers. ?- mostCommonSublist([1,2,2,3,2,2,4,2,2,3],3,L). L = [2,2,3] ; false. ?- mostCommonSublist([1,2,2,1,2,1,2,2,2,3],3,L). L = [1,2,2] ; L = [2,1,2] ; false. ?- mostCommonSublist([1,2,2,1,2,1,2,2,2,1],2,L). L = [1,2] ; L = [2,2] ; L = [2,1] ; false.
Implementation of predicate similar to Transpose in Prolog
I am pretty new to Prolog, actually 4 days into it and I came across an exercise that states : Given a list of N lists with N size each implement a predicate called reshape(X,Y) so that it : Collects the first elements of all lists into a list. Collects the second elements of all lists lists into a list. ... Collects the N elements of all lists into a list. Collects all lists mentioned above into a new list. An example would be : reshape([[1,2,3],[4,5,6],[7,8,9]],X) X = [[1,4,7],[2,5,8],[3,6,9]] So here is my implementation : % Insert at the end of a list insert([],X,[X]). insert([H|T1],X,[H|T2]) :- insert(T1,X,T2). % Length of list len([],L,L). len([_|T],L,X) :- L1 is L + 1, len(T,L1,X). len(L,X) :- len(L,0,X). % Create a list of N empty lists init_list(L,0,L) :- !. init_list(L,N,X) :- N1 is N-1, insert(L,[],Y), init_list(Y,N1,X). init_list(N,X) :- init_list([],N,X). % Assign each element of a list to the corresponding list. assign([],[],[]). assign([H1|T1],[H2|T2],[Y|T3]) :- insert(H2,H1,Y), assign(T1,T2,T3). % Reshape : reshape([],L,L). reshape([H1|T1],X,Result):- assign(H1,X,Y), reshape(T1,Y,Result). reshape(Input,Result) :- len(Input,N), init_list(N,X), reshape(Input,X,Result). So the basic idea is that I start by creating a list of N empty lists and then for each list say L of the input I assign/add each element of L to the corresponding list. Now I would appreciate some input as I already said I am new to Prolog and can't even tell what the time complexity of my predicate is.The only thing I know for a fact is that it works. Howerever is there a better way I can implement it? What's the time complexity of my implementation ? It seems like polynomial time but I can't really tell. Thanks in advance.
You can code an O(N) algorithm that just goes through each element once: reshape([[]|Tail], []):- maplist(=([]), Tail). reshape(Input, [Result|RTail]):- reshape(Input, LTail, Result), reshape(LTail, RTail). reshape([], [], []). reshape([[Item|Tail]|LTail], [Tail|MTail], [Item|RTail]):- reshape(LTail, MTail, RTail). reshape/3 gets the list with every first element of the list of lists. Then reshape/2 builds all such lists recursively. Test case: ?- reshape([[1,2,3],[4,5,6],[7,8,9]],X). X = [[1, 4, 7], [2, 5, 8], [3, 6, 9]] ; false.
Removing Duplicates while maintaining order in Prolog
I am trying to create a predicate that removes duplicates from a list while maintaining its relative order. For example a list that is [1,2,2,3,4,5,5,2] should return [1,2,3,4,5]. However, my code is only able to remove consecutive duplicates and for instance, not the 2 at the end. remove_duplicates([],[]). remove_duplicates([H],[H]). remove_duplicates([H,H|T],[H|List]) :- remove_duplicates(T,List). remove_duplicates([H,X|T],[H|T1]):- X\=H, remove_duplicates([X|T],T1). Another approach I was thinking of was to use member to see if the Tail contains the Head. However, the only way I can think of solving it that way is where I would remove the head, if head is a member of tail. This would however keep the last instance of the number only and break the relative order of the numbers in the list. For instance: [1,2,2,3,4,5,5,2] [1,3,4,5,2] When I actually want [1,2,3,4,5]
You can make use of an accumulator: an extra parameter, here a list that is initially empty and when new elements arise will grow. Each recursive call the list is passed (or an updated copy). For example: remove_duplicates(LA, LB) :- remove_duplicates(LA, LB, []). remove_duplicates([], [], _). remove_duplicates([H|T], R, Seen) :- ( member(H, Seen) -> (R = S, Seen1 = Seen) ; (R = [H|S], Seen1 = [H|Seen]) ), remove_duplicates(T, S, Seen1). This then gives us: ?- remove_duplicates([1,2,2,3,4,5,5,2], L). L = [1, 2, 3, 4, 5]. Of course you can make use of more effective datastructures than a list. I leave that as an exercise.
Shifting a list N times using Prolog [] issue :- Exercise 3.6 “ Prolog Programming for Artificial Intelligence” by Ivan Btrako
I want to create a predicate shift(List1,List2) where List2 is List1 shifted rotationally by one element to the left. Example: ?- shift([1,2,3,4],L1), shift(L1,L2), shift(L2,L3). L1 = [2, 3, 4, 1], L2 = [3, 4, 1, 2], L3 = [4, 1, 2, 3]. I created the predicate conc([],L,L). conc([X|T],L2,[X|T1]) :- conc(T,L2,T1). shift([H|T],L2) :- conc(T,H,L2). However, it's wrong & I don't understand why... It works only if the H is surrounded by [H]. shift([H|T],L2) :- conc(T,[H],L2). The predicate without the [ ] only works with 1 shift & it outputs the following: ?- shift([1,2,3,4],L1). L1 = [2, 3, 4|1]. Obviously, there's a basic concept I'm confused with, but I can't seem to pin-point what's wrong alone. I'm new at Prolog, so any help would be appreciated.
It works only if the H is surrounded by [H] As I noted before, conc/3 is really the standard predicate append/3 which takes in two list and creates a third list. append/3 says: append(?List1, ?List2, ?List1AndList2) List1AndList2 is the concatenation of List1 and List2 A single term is not a list, e.g. 1 is not a list, but [1] is a list. A list starts with [ and ends with ]. This is the empty list: [] A list can have one item: [a] or more than one item: [a,b] and so on. Notice how they always have square brackets. When you use conc/3 or append/3 all three values have to be list, so even if you want to concatenate or append a single item you have to convert it to a list first by surrounding it with [] to turn it into a list. So the single item 1 is converted to a list as [1].
PROLOG - Change elements in a list
I need to change elements in a list, I have the following code: change_aux(_,_,[],[]). change_aux(X,Y,[X|T],[Y|S]):-!,change_aux(X,Y,T,S). change_aux(X,Y,[Z|T],[Z|S]):-change_aux(X,Y,T,S). flatten2([], []) :- !. flatten2([L|Ls], FlatL) :- !, flatten2(L, NewL), flatten2(Ls, NewLs), append(NewL, NewLs, FlatL). flatten2(L, [L]). change(X,Y,[X1|Y1],[X2,Y2]):- flatten([X1|Y1],L), change_aux(X,Y,L,[X2|Y2]). Input: change(2,5,[1,[2,[3,2],1]],R). Print: R = [1, [5, 3, 5, 1]] . But I need R to be printed like this: R = [1,[5,[3,5],1]] Could you help me, please?
There are some problems in the code above like in definition change(X,Y,[X1|Y1],[X2,Y2]):- I don't think that the output list should always consists of two elements. Besides that the change_aux predicate needs some work since now it's just traversing the list and not building the nested output list. You could try something that would build recursively the nested levels of the list like: change(_,_,[],[]). change(X,Y,[H|T],[H|T1]):- \+is_list(H),dif(H,X),change(X,Y,T,T1). change(X,Y,[X|T],[Y|T1]):- change(X,Y,T,T1). change(X,Y,[H|T],[L|T1]):- is_list(H),change(X,Y,H,L),change(X,Y,T,T1). Note that in the above predicate there is no need to use flatten/2 predicate since we take advantage of the nested levels of input list to build output list. Example: ?- change(2,5,[1,[2,[3,2],1]],R). R = [1, [5, [3, 5], 1]] ; false.