Related
For an input like extract_column([[1,2], [3, 4], [5,6]], 0, X)., I'd like to see the result as [1,3,5]. I'm not sure if my base case is correct or how to proceed with the recursive logic.
The point is to get the Ith element of the header (list), append it to the result list R and recursively apply that logic to all of the lists inside the big list.
extract_column([], [R1]).
extract_column([H|T], I, [R]) :-
extract_column([T], I, [R1]),
nth0(I, [H], num1),
append([R], num1, R1).
Indeed, the base case is not correct and furthermore there is no need to use append/3.
The base case should define a predicate of arity 3 (i.e., with arguments Matrix, Index, Column).
To add an element Y to the beginning of a list Ys, just write [Y|Ys].
For more efficiency, it's better to use tail recursion (moving the recursive call to the end of the clause).
Thus, a possible solution is:
extract_column([], _, []).
extract_column([X|Xs], I, [Y|Ys]) :-
nth0(I, X, Y),
extract_column(Xs, I, Ys).
Examples:
?- extract_column( [[1,2], [3, 4], [5,6]], 0, Col).
Col = [1, 3, 5].
?- extract_column( [[1,2], [3, 4], [5,6]], I, Col).
I = 0,
Col = [1, 3, 5] ;
I = 1,
Col= [2, 4, 6].
For my assignment I need to create a list of all the possible shifts (rotations) of another list in prolog. For example,
Prototype: all_shifts(+A,-R,+L,+S) *S will always start at 1*
?- length([1,2,3,4],L), all_shifts([1,2,3,4],R,L,1).
L = 4,
R = [[2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]].
Currently, I have a program that shifts it to the left once.
one_shift(A, R) :-
rotate(left, A, R).
rotate(left, [H|T], L) :- append(T, [H], L).
However, I need to create another program in which the final result (R) contains all of the possible shifts. Recursion in prolog is really beginning to confuse me, but I'm pretty sure that's whats required. Any help would be really appreciated.
Stay logically pure using same_length/2 and append/3!
list_rotations(Es, Xss) :-
same_length(Es, [_|Xss]),
rotations_of(Xss, Es).
rotations_of([], _Es).
rotations_of([Xs|Xss], Es) :-
same_length([_|Xss], Suffix),
same_length(Es, Xs),
append(Suffix, Prefix, Xs),
append(Prefix, Suffix, Es),
rotations_of(Xss, Es).
Sample query:
?- list_rotations([A,B,C,D], Xss).
Xss = [[B,C,D,A],
[C,D,A,B],
[D,A,B,C]]. % succeeds deterministically
A solution to your problem could be:
rotatelist([H|T], R) :- append(T, [H], R).
rotate(L,LO,LL):-
rotatelist(L,L1),
\+member(L1,LO),!,
append([L1],LO,L2),
rotate(L1,L2,LL).
rotate(_,L,L).
?- rotate([1,2,3,4],[],L).
L = [[1, 2, 3, 4], [4, 1, 2, 3], [3, 4, 1, 2], [2, 3, 4, 1]]
Simply rotates the list and checks if this list has already been inserted in the output list. If not the recursion continues, otherwise it returns the list in L. I've inserted the cut ! just to have only the list with all the possible rotations. If you want generate also the other lists just remove it...
If instead you want a solution with the prototype you provide, it could be:
rotatelist([H|T], R) :- append(T, [H], R).
all_shifts(_,[],I,I).
all_shifts(L,Result,Len,I):-
I < Len,
rotatelist(L,LO),
I1 is I+1,
all_shifts(LO,R1,Len,I1),
append([LO],R1,Result).
?- length([1,2,3,4],L), all_shifts([1,2,3,4],R,L,1).
L = 4,
R = [[2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
The idea is basically the same as before... Note that this second solution is not tail recursive.
I am having a bit of trouble with prolog as I have just started learning it. I am unsure how to test if X is the median of A, B, C. My first thought was to make a list of A, B, C and then sort it. I would then check if X is equal to the second number. The problem being that I don't know how to take three values and turn them into a list (If you can). Is this even the most effecent way to do this? Honestly I have no Idea so any insite would be helpful.
this is a very basic solution, with a sorting only accepting 3 values, but it should make the problem solved.
is_median_of_sorted([_, ValueToCheck, _],ValueToCheck).
sorted_list_of_3([A,B,C],R) :-
A>B, A>C, B>C, R = [A,B,C];
A>C, A>B, C>B, R = [A,C,B];
B>A, B>C, A>C, R = [B,A,C];
B>C, B>A, C>A, R = [B,C,A];
C>A, C>B, A>B, R = [C,A,B];
C>B, C>A, B>A, R = [C,B,A].
is_median_of_3(List, ValueToCheck) :-
sorted_list_of_3(List,SortedList),
is_median_of_sorted(SortedList, ValueToCheck).
To check it, query:
is_median_of_3([1,10,4],4).
Or if you want to check what is the median of a given list:
is_median_of_3([1,10,4],X).
You can also check it via browser at: https://swish.swi-prolog.org/p/three_values_median.pl
What is does is : is_median_of_3 first gets a matching sorted list, and then checks agains is_median_of_sorted, which just picks a 2nd element of the list.
Hope I could help.
If you want to create a modular program, you had to insert all the elements in a list, sort it and find the median. This could be done in this way:
findMedian([H|_],0,H):- !.
findMedian([_|T],C,X):-
C1 is C-1,
findMedian(T,C1,X).
median(L,X):-
msort(L,SortedL),
length(SortedL,Len),
Len2 is Len//2,
findMedian(SortedL,Len2,X).
?- median([1,10,4,5,7],X).
X = 5
?- median([1,10,4,5,7],5).
true
This solution will works also with list with an even number of elements, returning the element after the middle of the list (ex. 4 elements, [0,1,2,3], it returns 2). In this case you have to decide what to do (fail, return the two elements in the middle ecc...)
EDIT: as suggested in the comment, you should use msort/2 instead sort/2 because sort/2 removes duplicated elements.
I would choose a solution similar to #damianodamiano's, but I would find the middle element of a list without using length/2:
median(List, Median) :-
msort(List, SortedList),
middle_element(SortedList, SortedList, Median).
middle_element([], [M|_], M).
middle_element([_], [M|_], M).
middle_element([_,_|Xs], [_|Ys], M) :-
middle_element(Xs, Ys, M).
A simple answer to "check if X is the median of A,B,C?" is:
is_median_of_3(A,B,C,X):-
msort([A,B,C],[_,X,_]).
This will try to match if [A,B,C] sorted consists of any list (of three elements) with X as the middle element.
I don't know everywhere, but in swish there are residuals coming out from msort as such:
msort([2,8,4],L).
L = [2, 4, 8],
_residuals = []
L = [2, 4, 8],
_residuals = [_1080]
L = [2, 4, 8],
_residuals = [_1122, _1128]
L = [2, 4, 8],
_residuals = [_1170, _1176, _1182]
L = [2, 4, 8],
_residuals = [_1224, _1230, _1236, _1242]
L = [2, 4, 8],
_residuals = [_1284, _1290, _1296, _1302, _1308]
L = [2, 4, 8],
_residuals = [_716, _722, _728, _734, _740, _746]
L = [2, 4, 8],
_residuals = [_788, _794, _800, _806, _812, _818, _824]
L = [2, 4, 8],
_residuals = [_866, _872, _878, _884, _890, _896, _902, _908]
and so on...
Also, I couldn't test it in tutorialspoint because it seems broken.
Following a generate & test approach you can write:
median(List,Median) :-
dif(List,[]), msort(List,SList), length(List,Len),
append(Low,[Median],Tmp), append(Tmp,High,SList),
length(Low,LowLen), div(Len,2)=:=LowLen, !.
This has a convenient declarative reading: Median is the value of a non-empty List that splits the sorted version SList of List into two halves Low and High, viz. Median is the "middle element" of the distribution of the values in List.
Indeed, the program above determines Median by checking whether SList can be written as a list concatenation Low + [Median] + High such that the length of Low is half the length of SList. Since High is never used (i.e. it is a singleton), the program can be rewritten by substituting it with _ as in:
median(List,Median) :-
dif(List,[]), msort(List,SList), length(List,Len),
append(Low,[Median],Tmp), append(Tmp,_,SList),
length(Low,LowLen), div(Len,2)=:=LowLen, !.
Naturally, it is also possible to distinguish the case in which the length of the list is odd from the case it is even, so to return the average of the two median elements in the latter case:
median(List,Median) :-
is_list(List), dif(List,[]),
msort(List,SList), length(List,Len),
median(SList,Len,Median).
median(SList,Len,Median) :-
Len mod 2 =:= 1,
append3(Low,[Median],_,SList),
length(Low,LowLen), div(Len,2)=:=LowLen, !.
median(SList,Len,Median) :-
Len mod 2 =:= 0,
append3(Low,[M1,M2],_,SList),
length(Low,LowLen), div(Len,2)=:=LowLen + 1,
Median is (M1+M2)/2, !.
append3(L1,L2,L3,L) :- append(L1,L2,T), append(T,L3,L).
I am trying to find the most common sequence of length N that occurs in a list. So I am supposed to write a predicate common(L,N,X) that gives me this sequence in a form of a list. For example: common([1,2,3,2,3,1,4],2,X) should give me back X=[2,3] ; common([1,2,3,4,2,2,2,3,4],3,X) should give back X=[2,3,4] or common([1,2,3],1,X) should give X=[1] X=[2] X=[3].
I have read a couple of posts when we seek only the most common element (so a case where N=1), but I don`t know how to do it for a general N. I am not allowed to use if-then-else or clpfd.
I was thinking maybe grouping the elements and then ordering them, so for common([1,2,3,2,3,1,4],2,X) make a list like this[[1,2],[2,3],[3,2],[2,3],[3,1],[1,4]] and then order the elements from most common to least.
I like your plan. Here's how I'd get the overlapping subsequences.
First, let's get the prefix of the list of length N:
subsequences(L, N, Sub) :- append(Sub, _, L), length(Sub, N).
This should be read "Sub is a subsequence of length N of list L if Sub, appended to something else yields L, and the length of Sub is N." This will definitely get you a prefix of L of length N. Now let's see the recursive case:
subsequences([_|L], N, Sub) :- subsequences(L, N, Sub).
"Otherwise, find a subsequence in the tail of L." And this will produce multiple solutions:
?- subsequences([1,2,3,2,3,1,4], 2, X).
X = [1, 2] ;
X = [2, 3] ;
X = [3, 2] ;
X = [2, 3] ;
X = [3, 1] ;
X = [1, 4] ;
findall/3 is your friend here, you can use it to build the list you want:
?- findall(X, subsequences([1,2,3,2,3,1,4], 2, X), Subsequences).
Subsequences = [[1, 2], [2, 3], [3, 2], [2, 3], [3, 1], [1, 4]].
Hope this helps!
When given some input list, I want to build a new list and it should:
Always add h in front of the new list
Compare every two consecutive elements of the input list, and, if they are
equal, append y to the new list, if not, append x.
Example:
?- control([a,a,b,b],R).
R = [h,y,x,y].
Here is my code so far:
control([H,H|T],K,[K,0|T2]):- control([H|T],[K,0],T2).
control([H,J|T],K,[K,1|T2]):- control([J|T],[K,1],T2).
control([H],G,G).
But it is not working correctly.
?- control([a,a,b,b],[h],L).
L = [[h], 0, [[h], 0], 1, [[[h], 0], 1], 0, [[[...]|...], 1], 0] ;
L = [[h], 0, [[h], 0], 1, [[[h], 0], 1], 1, [[[...]|...], 1], 1] ;
L = [[h], 1, [[h], 1], 1, [[[h], 1], 1], 0, [[[...]|...], 1], 0] ;
L = [[h], 1, [[h], 1], 1, [[[h], 1], 1], 1, [[[...]|...], 1], 1] ;
false.
How can I make it correct?
Here's another way you could take...
Based on if_/3 and (=)/3 define list_hxys/2:
list_hxys([E|Es], [h|Xs]) :-
list_hxys_prev(Es, Xs, E).
list_hxys_prev([], [], _).
list_hxys_prev([E|Es], [X|Xs], E0) :-
if_(E = E0, X = y, X = x),
list_hxys_prev(Es, Xs, E).
Some sample queries using SICStus Prolog 4.3.2:
| ?- list_hxys([a,a,b,b], Xs). % (query given by the OP)
Xs = [h,y,x,y] ? ; % expected answer
no
| ?- list_hxys(As, [h,y,x,y]). % works the "other" way around, too
As = [_A,_A,_B,_B],
prolog:dif(_B,_A) ? ; % answer with residual goal dif/2
no
Let's break it down:
% Two elements being read are the same -> add y
control([H,H|T],[y|R]) :- control([H|T],R).
% Two elements being read are not the same -> add x
control([H1,H2|T],[x|R]) :- H1 \== H2, control([H2|T],R).
In both clauses we make a recursive call with all but the first checked element and respectively add an 'x' or 'y' to the result.
Now it's up to you to define the base case, note however that depending on whether input lists have an even or uneven amount of elements, two base cases will be required: one for a list with a single element and one for an empty list.