7

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!

Jimeree
  • 549
  • 3
  • 10

4 Answers4

11

ReplaceAll should do it:

{{2, 4, 1}, {3, 1, 2}, {4, 3, 1}} /. {2 -> 3, 3 -> 2}
J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
P. Fonseca
  • 6,665
  • 2
  • 28
  • 60
9

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)]
kglr
  • 394,356
  • 18
  • 477
  • 896
  • Another way to generate the replacement rules: Dispatch[Apply[Join, Thread[# -> Reverse[#]] & /@ pairs]]. – J. M.'s missing motivation Aug 26 '12 at 11:21
  • @J.M. really nice. More concise than everything I have tried. – kglr Aug 26 '12 at 12:33
  • @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.) – Noble P. Abraham Aug 26 '12 at 13:24
  • 1
    @Noble P. Abraham That's probably because I asked for the original matrix to be replaced in my question. – Jimeree Aug 26 '12 at 13:36
  • That's true. Considering swap as a general function, it might be better if it does not replace. – Noble P. Abraham Aug 26 '12 at 13:42
  • 2
    @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. – kglr Aug 26 '12 at 13:53
4

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]
Nasser
  • 143,286
  • 11
  • 154
  • 359
3

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}} *)
VLC
  • 9,818
  • 1
  • 31
  • 60