Message Boards Message Boards

Efficient method to cyclically swap items in a list

Posted 9 years ago

Hi Everyone

Lets 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 advance

P.

POSTED BY: Paul Cleary
6 Replies

This may not be what you want, but you can try with a replacement rule:

a/.{1->2, 2->3, 3->4, 4->1}
POSTED BY: Gianluca Gorni
Posted 9 years ago

.

a /. MapThread[Rule, {Range[4], RotateRight[Range[4]]}]
POSTED BY: Bill Simpson
Posted 9 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 BY: Paul Cleary
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 BY: Gianluca Gorni

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 BY: Udo Krause
Posted 9 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 BY: Wiel Aerts
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract