first time stack exchange poster here! So I was working on a problem, the purpose of which was to write a function in the procedural style to rotate right the ith row of a matrix by i - 1 spaces. Ok, easy enough here was my implementation:

rotateRowsProcedural[mat_?MatrixQ] :=
  clonedMat = mat;
  i = 1;
  While[i <= Dimensions[clonedMat][[1]],
    clonedMat[[i]] = RotateRight[clonedMat[[i]], i - 1];

This was too boring so I decided I wanted to try and solve the problem using pattern matching approach and I came up with

rotateRowsPattern[matrix_?MatrixQ] := 
  matrix /. mat : {x__List} :> (RotateRight[#, Position[mat, #][[1, 1]] - 1] & /@ {x}) `

Now I thought this was pretty awesome I mean to me its the essence of Mathematica. However, I then decided to compare the efficiency of the two functions

Mean[Table[Timing[rotateRowsPattern[RandomInteger[{0, 10},{1000, 1000}]]][[1]], {100}]]


Mean[Table[Timing[rotateRowsProcedural[RandomInteger[{0,10},{1000,1000}]]][[1]], {100}]]


I was surprised that the procedural implementation was faster. Then I thought it over and I think it is the case that calling Position in the pattern implementation must slow things down. My question then is if I want to use pattern matching how can I reference the location of x (from x__List) so that I don't have to call Position.

Also, I'm aware that combining Map and Range would be the most concise way to do this but I'm interested in the pattern matching.

  • $\begingroup$ "Map and Range would be the most concise way..." - nope. There's MapIndexed[]... $\endgroup$ – J. M.'s torpor May 30 '13 at 6:00
  • $\begingroup$ This isn't using pattern matching but for a speed up this may help: rr[rin_] := (RotateRight[rin[[#]], # - 1] & /@ Range[Length[rin]]). $\endgroup$ – Jonathan Shock May 30 '13 at 6:07
  • 2
    $\begingroup$ I would also define your functions as Module as you are defining global variables (clonedmat) within them. It's best to keep track of the scope of such variables when you can. $\endgroup$ – Jonathan Shock May 30 '13 at 6:09
  • $\begingroup$ @LarryS, please feel free to ignore my comment in that case. You are right that you did explicitly say that and I had missed that point in your post, my apologies. $\endgroup$ – Jonathan Shock May 30 '13 at 6:22
  • 6
    $\begingroup$ @LarryS Be civil. People are only attempting to be helpful. Leaving stray global symbols in your function is bad programming practice and code exhibiting such will often be remarked upon. $\endgroup$ – Mr.Wizard May 30 '13 at 6:27

Since the summary of your question is:

My question then is if I want to use pattern matching how can I reference the location of x (from x__List) so that I don't have to call Position.

I believe it is a duplicate of: Position of a pattern-matched part of an expression

Nevertheless in an effort to be helpful I would like to comment on your code.

Your procedural function should use Module to localize the Symbols that you use. It would also be more efficient to calculate the dimensions only once:

rotateRowsProcedural[mat_?MatrixQ] := 
 Module[{clonedMat = mat, i = 1, dims = Dimensions[mat][[1]]},
  While[i <= dims, clonedMat[[i]] = RotateRight[clonedMat[[i]], i - 1]; i++;];

Your pattern based function is a bit confusing. The pattern matching is purely incidental to the operation of the function itself which could be written simply:

rotateRowsPattern[matrix_?MatrixQ] := 
 RotateRight[#, Position[matrix, #][[1, 1]] - 1] & /@ matrix

But both this function and yours will fail of there are repeated rows in the matrix.

You will see from the linked question above that there is no known easy and general solution to the problem of getting the position of a matched pattern. However, for this simple application you can simply increment a counter for each row that is matched, which is perhaps in the spirit of what you intend:

rotateRows1[m_?MatrixQ] :=
  Module[{i = 0}, m /. x_?VectorQ :> RotateRight[x, i++]]

Still, this might be better formulated without the pattern matching as:

rotateRows2[m_?MatrixQ] := Module[{i = 0}, RotateRight[#, i++] & /@ m]

But this is really nothing more than a manual implementation of MapIndexed:

rotateRows3[m_?MatrixQ] := MapIndexed[RotateRight[#, #2[[1]] - 1] &, m]
  • $\begingroup$ One could of course do Length[mat] instead of Dimensions[mat][[1]]. Using While[] here looks a bit clunky; I'd have used Do[] myself. $\endgroup$ – J. M.'s torpor May 30 '13 at 6:39
  • $\begingroup$ @J.M. Agreed. I was attempting to work with the OP's style, for what it's worth. $\endgroup$ – Mr.Wizard May 30 '13 at 6:55
  • $\begingroup$ @Mr.Wizard (of Oz) thanks for the link. I'm somewhat disappointed that matched elements from the pattern matcher don't know by default their position but thus is life. $\endgroup$ – John Smith May 30 '13 at 15:16

You could consider using MapIndexed just to "tag" each row with its row number and then use a replacement rule from there:

rot[mat_] := MapIndexed[List, mat] /. {x_, i_} :> RotateRight[x, i - 1]

Faster, but less readable, is to use Transpose and Range instead of MapIndexed:

rot[mat_] := Transpose[{mat, Range@Length@mat}] /. {x_, i_} :> RotateRight[x, i - 1]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.