7
$\begingroup$

Is there a nice, simple script one can use to swap two entires in a matrix? For example, suppose we have the matrix below:

$A=\begin{pmatrix}2 & 4 & 1\\ 3 & 1 & 2\\ 4 & 3 & 1 \end{pmatrix}$

Is there a script of the form switch[A,a,b], which will swap all occurrences of $a$ in the matrix with $b$, and vice versa, and then update the matrix $A$ accordingly? So in this case the output of switch[A,2,3] would be:

$A=\begin{pmatrix}3 & 4 & 1\\ 2 & 1 & 3\\ 4 & 2 & 1 \end{pmatrix}$

My own solution involves a lot of If and For functions, and will, I think, also run into the problems detailed here. I think it will work eventually (and I'd be happy to post what I have so far if people would like), but really I'm just wondering whether there's a simpler way to do this.

Thanks!

$\endgroup$
9
$\begingroup$

A minor point regarding ReplaceAll: ReplaceAll does not change the matrix a, so you do need to set a= (a/. {replacement rules}) or a=ReplaceAll[a,{replacement rules}].

 a = {{2, 4, 1}, {3, 1, 2}, {4, 3, 1}};
 a = (a /. {2 -> 3, 3 -> 2});
 a // MatrixForm

enter image description here

Another alternative is to use Replace at level 2:

 a = Replace[a, {2 -> 3, 3 -> 2}, {2}] 

or at level -1:

 a = Replace[a, {2 -> 3, 3 -> 2}, {-1}] 

Yet another alternative:

 a = Cases[a, {x___, aa : (3 | 2), y___} :> {x, If[aa == 3, 2, 3], y}, {1,Infinity}]

Update: functions to swap a pair of elements of a matrix:

ClearAll[swap];
SetAttributes[swap, HoldFirst];
swap[mat_, elem1_, elem2_] := (mat = mat /. {elem1 -> elem2, elem2 -> elem1})
swap[a,2,3]
 (* {{3, 4, 1}, {2, 1, 3}, {4, 2, 1}} *)

Swap multiple pairs of elements:

ClearAll[swap2];
SetAttributes[swap2, HoldFirst];
swap2[mat_, pairs:{{_, _} ..}] := (mat = mat /.(Rule @@@ Join[pairs, Reverse /@ pairs]))
swap2[a,{{2,3}}]
 (* {{2, 4, 1}, {3, 1, 2}, {4, 3, 1}}  *)
swap2[a,{{2,3},{1,4}}]
 (* {{3, 1, 4}, {2, 4, 3}, {1, 2, 4}} *)

For large matrices and many pairs to swap:

ClearAll[swap3];
SetAttributes[swap3, HoldFirst];
swap3[mat_, pairs : {{_, _} ..}] :=  With[{dispatch = Dispatch[Rule @@@ Join[pairs, Reverse /@ pairs]]}, mat = (mat /. dispatch)]
$\endgroup$
  • $\begingroup$ Another way to generate the replacement rules: Dispatch[Apply[Join, Thread[# -> Reverse[#]] & /@ pairs]]. $\endgroup$ – J. M. will be back soon Aug 26 '12 at 11:21
  • $\begingroup$ @J.M. really nice. More concise than everything I have tried. $\endgroup$ – kglr Aug 26 '12 at 12:33
  • $\begingroup$ @kguler Won't it be better if the swap function do not replace the original matrix itself? (I mean, if both a and swapped a are needed.) $\endgroup$ – Noble P. Abraham Aug 26 '12 at 13:24
  • 1
    $\begingroup$ @Noble P. Abraham That's probably because I asked for the original matrix to be replaced in my question. $\endgroup$ – Jimeree Aug 26 '12 at 13:36
  • 2
    $\begingroup$ @NobleP.Abraham, I agree with you. To get a version that does not replace the input matrix, one can remove the part mat= in the definition of swap and use a=swap[a,...] when one needs to replace a. $\endgroup$ – kglr Aug 26 '12 at 13:53
11
$\begingroup$

ReplaceAll should do it:

{{2, 4, 1}, {3, 1, 2}, {4, 3, 1}} /. {2 -> 3, 3 -> 2}
$\endgroup$
4
$\begingroup$

I like the above ReplaceAll solution the most. But to make sure there are at least 10 different ways to do something in Mathematica, here is another way

mat = {{2, 4, 1}, {3, 1, 2}, {4, 3, 1}};
pos1 = Position[mat, 2];
pos2 = Position[mat, 3];
mat = ReplacePart[mat, pos1 -> 3];
mat = ReplacePart[mat, pos2 -> 2]
$\endgroup$
3
$\begingroup$

With ReplacePart and Position:

a = {{2, 4, 1}, {3, 1, 2}, {4, 3, 1}};
ReplacePart[a, {Position[a, 2] -> 3, Position[a, 3] -> 2}]

(* {{3, 4, 1}, {2, 1, 3}, {4, 2, 1}} *)
$\endgroup$

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.