# Efficient method to cyclically swap items in a list

Posted 8 years ago
7878 Views
|
6 Replies
|
2 Total Likes
|
 Hi EveryoneLets say I have a list a = {15, 5, 14, 1, 6, 10, 9, 2, 13, 7, 16, 17, 11, 20, 8, 19, 18, 12, 3, 4} and I wish to swap the numbers {1, 2, 3, 4} or more specifically rotate that sub list left or right within the larger list, of course the sub list could be any 4 numbers or more than 4.My method has been to find the position of the 4 numbers in the main list and then working with a temporary variable for the first value, do a replace procedure and then the last number takes the value of the temp variable. It works ok but seems clumsy and not very expandable in that it needs a rewrite if I alter the number of items to swap. can any one see a more efficient method?Thanking everyone in advanceP.
6 Replies
Sort By:
Posted 8 years ago
 You could also use Permutations. pos = Map[Position[a, x_ /; x == #] &, {1, 2, 3, 4}] // Flatten Then just permute your list, 4 times: Table[a = Permute[a, Cycles[{pos}]] , {i, 4}] {{15, 5, 14, 3, 6, 10, 9, 4, 13, 7, 16, 17, 11, 20, 8, 19, 18, 12, 1, 2}, {15, 5, 14, 2, 6, 10, 9, 3, 13, 7, 16, 17, 11, 20, 8, 19, 18, 12, 4, 1}, {15, 5, 14, 1, 6, 10, 9, 2, 13, 7, 16, 17, 11, 20, 8, 19, 18, 12, 3, 4}, {15, 5, 14, 4, 6, 10, 9, 1, 13, 7, 16, 17, 11, 20, 8, 19, 18, 12, 2, 3}} 
Posted 8 years ago
 a/.{1->2, 2->3, 3->4, 4->1} rotates left: as the arrows indicate, it replaces 1 with 2, 2 with 3, 3 with 4 and 4 with 1. a/.{1 -> 4, 2 -> 1, 3 -> 2, 4 -> 3} rotates right: it replaces 1 with 4, 2 with 1, 3 with 2 and 4 with 3. a/.Thread[Range[4] -> RotateRight[Range[4]]] does the exact same thing, because Thread[Range[4] -> RotateRight[Range[4]]] evaluates to {1 -> 4, 2 -> 1, 3 -> 2, 4 -> 3} 
Posted 8 years ago
 Gianluca, will definitely play with that method, even though it didn't see to behave as expected, However, Bill absolutely perfect, that does exactly what I need, thank you.
Posted 8 years ago
 Another way Clear[clearySubRotate] clearySubRotate[l_List?VectorQ, n_Integer (* length sublist *), m_Integer (* left rotate, negative: right *)] := Flatten[RotateLeft[#, m] & /@ Partition[l, n], 1] /; n > 0 && Mod[Length[l], n] == 0 In[30]:= clearySubRotate[Join @@ (Array[#, 7] & /@ {a, b, c, d}), 7, 3] Out[30]= {a[4], a[5], a[6], a[7], a[1], a[2], a[3], b[4], b[5], b[6], b[7], b[1], b[2], b[3], c[4], c[5], c[6], c[7], c[1], c[2], c[3], d[4], d[5], d[6], d[7], d[1], d[2], d[3]} 
Posted 8 years ago
 . a /. MapThread[Rule, {Range[4], RotateRight[Range[4]]}] 
Posted 8 years ago
 This may not be what you want, but you can try with a replacement rule: a/.{1->2, 2->3, 3->4, 4->1}