Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swap last two elements of a list in Prolog

Tags:

list

prolog

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.

like image 592
BillyRater Avatar asked Dec 08 '21 20:12

BillyRater


People also ask

How do you find the last element of a list in Prolog?

You just want the last element of the list. Try this: lastElement([Head]) :- write(Head). lastElement([_|Tail]):- lastElement(Tail).

How do I remove the last element in a list in Prolog?

Count the number of element in the list before call the predicate that delete the last element. Iterate by recursion and decrement the value of the number of element each time. If it is true that the number of element is 0 it means that this is the last element so I delete it from the original list.

How do you get the second element in a list in Prolog?

You can move unification into the head of the clause and simply write: second([_, Second| _], Second). The notation for lists is to write the initial elements separated by commas and then a vertical bar to separate the list tail, i.e. the list containing the rest of the elements.

How do you select an element in a list in Prolog?

This predicate can be used to select an element from a list, delete an element or insert it. The definition of this Prolog library predicate is: select(A, [A|B], B). select(A, [B, C|D], [B|E]) :- select(A, [C|D], E).


2 Answers

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.
like image 172
slago Avatar answered Oct 14 '22 03:10

slago


Using first-argument indexing, and improved performance by removing the unnecessary reverse(), and also same_length():

swap_last_2([Elem1, Elem2|Tail], SwappedLst, Last2) :-
    % same_length would prevent an unwanted choicepoint on: swap_last_2(L, [a,b], SL).
    %same_length([Elem1, Elem2|Tail], SwappedLst),
    swap_last_2_(Tail, Elem1, Elem2, SwappedLst, Last2).


% Swap the last 2 elements
swap_last_2_([], Elem1, Elem2, [Elem2, Elem1], [Elem2, Elem1]).

swap_last_2_([Head|Tail], Elem1, Elem2, [Elem1|SwappedLst], Last2) :-
    % Move the elements along
    swap_last_2_(Tail, Elem2, Head, SwappedLst, Last2).

Result in swi-prolog:

?- swap_last_2([4, 5, 6], [4, 6, 5], X).
X = [6,5].

Performance comparison (this method is fastest):

?- cmp(1000, 1000).
% 7,011,001 inferences, 0.503 CPU in 0.497 seconds (101% CPU, 13941510 Lips)
% 2,001,001 inferences, 0.282 CPU in 0.278 seconds (101% CPU, 7098617 Lips)
% 2,007,001 inferences, 0.205 CPU in 0.203 seconds (101% CPU, 9782721 Lips)
% 1,002,001 inferences, 0.063 CPU in 0.063 seconds (101% CPU, 15819840 Lips)
like image 23
brebs Avatar answered Oct 14 '22 02:10

brebs