Question

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].
  • List1 is the list i got to swap second and penultimate (second last) element.
  • X is the penultimate element.
  • List2 is the new list with the swapped elements.
Was it helpful?

Solution 2

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).

OTHER TIPS

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

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top