Good Morning
I have a list in following format:
[(1-4),(2-4), (3-4)]
I'd like to change it to:
[4,3,4,2,4,1]
I have tried 2 programs:
changeList([], Z) :-
write(Z).
changeList([(A-B)|T], Z) :-
append([A], Z, Y),
append([B], Y, X),
changeList(T, X).
and the second one:
changeList([],Z) :-
write(Z).
changeList([(X-Y)|T], Z) :-
W = [X|Z],
C = [Y|W],
changeList(T,C).
Sadly the result is always: [4,3,4,2,4,1|_38]. Where do i make a mistake?
You can solve your problem with different metods. If you want to get the list in reverse order, you need a further input variable which is an empty list. Using your code you can write:
changeList([],Z,Z).
changeList([(A-B)|T],Acc,Z) :-
append([A], Acc, Y),
append([B], Y, X),
changeList(T,X,Z).
?- changeList([(1-4),(2-4),(3-4)],[],Z).
Z = [4, 3, 4, 2, 4, 1]
You can avoid the use of append/3 in this way:
myReverse([],Z,Z).
myReverse([(A-B)|T],Acc,Z):-
myReverse(T,[B,A|Acc],Z).
?- myReverse([(1-4),(2-4),(3-4)],[],Z).
Z = [4, 3, 4, 2, 4, 1]
You have another solution which is to print the list in an ordered way, then reverse it using built-in predicate (in SWI) reverse/2:
changeListOrd([],[]).
changeListOrd([(A-B)|T], [A,B|TL]):-
changeListOrd(T,TL).
change(L,Lout):-
changeListOrd(L,L1),
reverse(L1,Lout).
?- change([(1-4),(2-4),(3-4)],Z).
Z = [4, 3, 4, 2, 4, 1]
I suggest you to go with the second solution (myReverse/3) so you don't need both append/3 and reverse/2.
foldl/4 is a friend for you :
changeList(In, Out) :-
foldl(reverse_one, In, [], Out).
reverse_one((X-Y), In, [Y,X|In]).
Example :
?- changeList([(1-4),(2-4),(3-4)],Out).
Out = [4, 3, 4, 2, 4, 1].
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].
I'm trying to create list2 from list1, but every member should have Z increment.
if Z=1 then: [1,2,3] -> [2,3,4]
addZ(Z,[X | Xs],[Y | Ys]):-
Y is X+Z,
addZ(Z,Xs,Ys).
If I try addZ(1,[1,2,3],X). I just get no as answer.
After adding the base case, as recommended by #DavidTonhofer, you can change the order of the first two arguments of the predicate to avoid spurious choice points (since Prolog apply first argument indexing to quickly narrow down applicable clauses):
addZ([], _, []).
addZ([X|Xs], Z, [Y|Ys]):-
Y is X + Z,
addZ(Xs, Z, Ys).
Example:
?- addZ([1,2,3], 1, Z).
Z = [2, 3, 4].
?-
As always the most fun starts when you use CLP, like
:- use_module(library(clpz)).
addZ(_, [], []).
addZ(I, [X|Xs], [Y|Ys]) :-
Y #= I + X,
addZ(I, Xs, Ys).
And now you can do stuff like:
?- addZ(1, [1, 2, 3], C).
C = [2,3,4].
?- addZ(1, [1, 2, X], [X, Y, 9]).
false.
?- addZ(4, [1, 2, X], [A, Y, 9]).
A = 5, Y = 6, X = 5.
?- addZ(I, [1, 2, X], [5|Ys]).
I = 4, Ys = [6,_A], clpz:(4+X#=_A).
Here's another solution using maplist/3 and library yall:
addZ(Z, Xs, Ys):-
maplist({Z}/[X, Y]>>(Y is X+Z), Xs, Ys).
Sample runs
?- addZ(1, [1,2,3], X).
X = [2, 3, 4].
?- addZ(5, [1,2,3], X).
X = [6, 7, 8].
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.
How can I reverse pairs of some list in Prolog?
For example:
?- reversePairs([1,2,3,4,5,6,7,9], R).
R = [2,1,4,3,6,5,9,7]. % expected answer
So far, I have written the following code:
reversePairs([X,Y|Xs], ReversedList) :-
reversePairs([X,Y|Xs], [], ReversedList).
reversePairs([], ReversedList, ReversedList).
reversePairs([X,Y|Xs], Accum, ReversedList) :-
reversePairs(Xs, [X,Y|Accum], ReversedList).
My code gives me the following answer:
?- reversePairs([1,2,3,4,5,6,7,9], R).
R = [7,9,5,6,3,4,1,2]. % observed answer
How can I correct my code to get the answer I want? Any suggestion?
Simply :
reversePairs([],[]).
reversePairs([X,Y|T], [Y,X|RT]) :-
reversePairs(T, RT).
This code fails if the number of elements is odd. What do you want to do for this case ?
Here's a funny possibility with DCGs:
reverp, [B,A] --> [A,B], !, reverp.
reverp --> [].
reversePairs(L1,L2) :- phrase(reverp,L1,L2).
It will also work on lists with odd number of elements.
Sample query:
?- reversePairs([1,2,3,4,5,6,7,9], R).
R = [2, 1, 4, 3, 6, 5, 9, 7].
?- reversePairs([1,2,3,4,5,6,7,8,9], R).
R = [2, 1, 4, 3, 6, 5, 8, 7, 9].
Can be easily generalized to N elements:
revern(N), Lr --> { length(L,N) }, L, !, { reverse(L,Lr) }, revern(N).
revern(_) --> [].
reverseNuples(N,L1,L2) :- phrase(revern(N),L1,L2).
Sample query:
?- reverseNuples(3,[1,2,3,4,5,6,7,9],R).
R = [3, 2, 1, 6, 5, 4, 7, 9].
As #repeat mentions in a comment below, reversePairs is not symmetric: the query
?- reversePairs(L,[2,1,4,3,6,5]).
will loop forever. To fix that, we can use same_length/2, to ensure that both terms are lists with same length:
reversePairs(L1,L2) :-
same_length(L1,L2),
phrase(reverp,L1,L2).
Hi I want to write a function called perfect_part that takes a list of integers as input and if possible, return two sub-lists whose sum is exactly half of the total values of all integers in original list.
For example,
?- perfect_part([6, 3, 2, 1], L, R).
L = [6],
R = [3, 2, 1] ;
false.
?- perfect_part([1, 2, 3, 4, 0], L, R).
L = [1, 4],
R = [2, 3, 0] ;
L = [2, 3],
R = [1, 4, 0] ;
Here is my try:
listsum([], 0).
listsum([H|T], Total):-
listsum(T, Sum1),
Total is H + Sum1.
subset([],L).
subset([X|T],L):- member(X,L),subset(T,L).
perfect_part([], 0, 0).
perfect_part(Nums, Left, Right):-
listsum(Nums, S),
H is S / 2,
subset(Left, Nums),
subset(Right, Nums),
listsum(Left, H),
listsum(Right, H).
But if I run it, I got error message:
ERROR: is/2: Arguments are not sufficiently instantiated
How can I fix it? Am I on the right track to sovle this problem?
The predicate subset/2 is missing, and it's an essential part to answer your question. Specifically, if sublists are contiguous, you can solve as easily as
perfect_part(X,L,R) :- append(L,R,X), listsum(L,S), listsum(R,S).
Then I would look for a more adequate replacement for append/3, like
partition([],[],[]).
partition([H|T],[H|L],R) :- partition(T,L,R).
partition([H|T],L,[H|R]) :- partition(T,L,R).
that leads to
perfect_part(X,L,R) :- partition(X,L,R), listsum(L,S), listsum(R,S).
edit Now, from subset/2 it's apparent the error cause: in base case, L is unbound.
Should be subset([],[])., but it doesn't terminate. I wonder how you get the error...
more edit To avoid duplicate solutions, I suggest to break the symmetry with
perfect_part(X,L,R) :- partition(X,L,R), L #=< R, listsum(L,S), listsum(R,S).