Reputation: 35
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.Upvotes: 2
Views: 1111
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
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
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