John
John

Reputation: 35

Swap second and prelast element from a list prolog

Well, for the last few hours, I've been trying to swap the second item of a given list with its penultimate item (the second last). Give the list [a,b,c,d,e,f], I want to get [a,e,c,d,b,f]. For example:

correct(List1,X,List2)
?-correct([a,y,b,c,d,e,x,f],x,List2).
List2[a,x,b,c,d,e,y,f].

Upvotes: 2

Views: 1111

Answers (3)

lurker
lurker

Reputation: 58234

This will work for lists of length 4 or greater:

correct( [H1|[H2|T1]], X, [H1|[X|T2]] ) :-
   reverse(T1, [HR|[X|TR]]),
   reverse([HR|[H2|TR]], T2).

| ?- correct( [1,2,3,4,5,6], X, L ).

L = [1,5,3,4,2,6]
X = 5

(1 ms) yes
| ?-

You can include the shorter cases, if that's the intention, by adding two more predicates, bringing the solution to:

correct( [A,X], X, [X,A] ).
correct( [A,X,B], X, [A,X,B] ).
correct( [H1|[H2|T1]], X, [H1|[X|T2]] ) :-
   reverse(T1, [HR|[X|TR]]),
   reverse([HR|[H2|TR]], T2).

Upvotes: 1

Paulo Moura
Paulo Moura

Reputation: 18663

The solutions posted by mbratch and CapelliC both fail for the following base case:

?- correct([a,y], X, List2).
false.

The following solution takes care of this base case and doesn't rely on list predicates that may or may not be available. It traverses the list once and is more efficient than the other two solutions:

correct([PreLast, Second], Second, [Second, PreLast]) :-
    !.
correct([First, Second, Last], Second, [First, Second, Last]) :-
    !.
correct([First, Second| InRest], PreLast, [First, PreLast| OutRest]) :-
    correct_aux(InRest, Second, PreLast, OutRest).

correct_aux([PreLast, Last], Second, PreLast, [Second, Last]) :-
    !.
correct_aux([Other| InRest], Second, PreLast, [Other| OutRest]) :-
    correct_aux(InRest, Second, PreLast, OutRest).

Sample queries:

?- correct([a,b], X, List).
X = b,
List = [b, a].

?- correct([a,b,c], X, List).
X = b,
List = [a, b, c].

?- correct([a,b,c,d], X, List).
X = c,
List = [a, c, b, d].

?- correct([a,b,c,d,e], X, List).
X = d,
List = [a, d, c, b, e].

Upvotes: 2

CapelliC
CapelliC

Reputation: 60004

another available builtin is append/2:

3 ?- [user].
correct(L, X, R) :- append([[A,B],C,[X,E]], L), append([[A,X],C,[B,E]], R).
|: 
% user://2 compiled 0.02 sec, 2 clauses
true.

4 ?- correct( [1,2,3,4,5,6], X, L ).
X = 5,
L = [1, 5, 3, 4, 2, 6] ;

I like mbratch one (+1), maybe this solution is more intuitive.

Upvotes: 1

Related Questions