Home > Blockchain >  Swap last two elements of a list in Prolog
Swap last two elements of a list in Prolog

Time:12-11

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].
  • Related