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$

4 Answers 4

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$
6
  • $\begingroup$ Another way to generate the replacement rules: Dispatch[Apply[Join, Thread[# -> Reverse[#]] & /@ pairs]]. $\endgroup$ Aug 26, 2012 at 11:21
  • $\begingroup$ @J.M. really nice. More concise than everything I have tried. $\endgroup$
    – kglr
    Aug 26, 2012 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$ Aug 26, 2012 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, 2012 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, 2012 at 13:53
11
$\begingroup$

ReplaceAll should do it:

{{2, 4, 1}, {3, 1, 2}, {4, 3, 1}} /. {2 -> 3, 3 -> 2}
$\endgroup$
0
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 and acknowledge you have read our privacy policy.

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