I've been trying to write a program that compares two lists hat are the same except the last two elements of List 2 are in reverse order, i.e [4,5,6] and [4,6,5], and that returns the last two elements that have been swapped.
For example:
SwapLastTwo([4, 5, 6] , [ 4, 6, 5], X).
should return
X = [6, 5]
So far my code looks like this:
lastTwoReversed([Z,A|T],[_,Y,X]) :-reverse([Z,A|T],[Y,X|_]).
My predicate so far only takes two arguments and checks, if are the same except the last two elements of List 2 are in reverse order and returns true
, if the condsitions are met
I don't know how I can modify my predicate to incoparate the X
as its third argument and make it return the swapped elements.
CodePudding user response:
Try this:
lastTwoReversed(L1, L2, [X1,X2]) :-
reverse(L1, [X1,X2|Rest]),
reverse(L2, [X2,X1|Rest]).
Notice that by using the variable Rest
in both subgoals, you establish that the lists must be the same, except for the last two items (which are swapped).
Example:
?- lastTwoReversed([1,2,3,4,5,6], [1,2,3,4,6,5], R).
R = [6, 5].
?- lastTwoReversed([1,2,3,4,5,6], [1,2,3,6,5], R).
false.
?- lastTwoReversed([1,2,3,4,5,6], [1,2,3,4,5,6], R).
false.
CodePudding user response:
Using first-argument indexing, to prevent a redundant choicepoint:
swap_last_2([Elem1, Elem2|Tail], SwappedLst) :-
swap_last_2_(Tail, Elem1, Elem2, [], RevSwappedLst),
reverse(RevSwappedLst, SwappedLst).
% This swaps the last 2 elements
swap_last_2_([], Elem1, Elem2, SoFar, [Elem1, Elem2|SoFar]).
swap_last_2_([Head|Tail], Elem1, Elem2, SoFar, SwappedLst) :-
% Move the elements along
swap_last_2_(Tail, Elem2, Head, [Elem1|SoFar], SwappedLst).
Result in swi-prolog:
?- time(swap_last_2([a, b, c, d, e, f], SWL2)).
% 14 inferences, 0.000 CPU in 0.000 seconds (86% CPU, 361692 Lips)
SWL2 = [a,b,c,d,f,e].
Has generality:
?- swap_last_2(List, SWL2).
List = [$VAR(_A),$VAR(_B)],
SWL2 = [$VAR(_B),$VAR(_A)] ;
List = [$VAR(_A),$VAR(_B),$VAR(_C)],
SWL2 = [$VAR(_A),$VAR(_C),$VAR(_B)] ;
List = [$VAR(_A),$VAR(_B),$VAR(_C),$VAR(_D)],
SWL2 = [$VAR(_A),$VAR(_B),$VAR(_D),$VAR(_C)]
To include the 2 elements swapped:
swap_last_2([Elem1, Elem2|Tail], SwappedLst, Last2) :-
swap_last_2_(Tail, Elem1, Elem2, [], RevSwappedLst, Last2),
reverse(RevSwappedLst, SwappedLst).
% This swaps the last 2 elements
swap_last_2_([], Elem1, Elem2, SoFar, [Elem1, Elem2|SoFar], [Elem2, Elem1]).
swap_last_2_([Head|Tail], Elem1, Elem2, SoFar, SwappedLst, Last2) :-
% Move the elements along
swap_last_2_(Tail, Elem2, Head, [Elem1|SoFar], SwappedLst, Last2).
Result in swi-prolog:
?- swap_last_2([4, 5, 6], [4, 6, 5], X).
X = [6,5].