# swap elements in a matrix depending on a condition

I want to perform some operations on a matrix depending on some condition. The matrix is:

mat1={{0.2,a1,b1,c1},{0.8,a2,b2,c2},{0.3,a3,b3,c3}}

• when the element in the first column is less than 0.5: nothing should happen to that specific row;
• when the element in the first column is larger than 0.5: I want to swap the second and the third element and define the fourth as their ratio;

For the above matrix, this operation should return:

mat2={{0.2,a1,b1,c1},{0.8,b2,a2,a2/b2},{0.3,a3,b3,c3}}


I would also like to keep track of the rows where it was necessary to make the swap operation.

what is the most efficient way to perform this operation in Mathematica?

The following quickly does the requested transformation.

mat2 = mat1 /. {z1_, z2_, z3_, _} /; z1 > 0.5 -> {z1, z3, z2, z2/z3}
(* {{0.2, a1, b1, c1}, {0.8, b2, a2, a2/b2}, {0.3, a3, b3, c3}} *)


One way to identify which rows were transformed is

# > .5 & /@ First@Transpose[mat1]
(* {False, True, False} *)

# > .5 & /@ mat2[[All, 1]]


gives the same result, as do several other options.

Efficiency: The computations just described are very fast. Applied to a 1000000 row matrix, the transformation in the first line of code takes about 1.6 sec, while determining which rows were transformed (the second line of code) takes about 0.5 sec.

• works like a charm! and indeed is very fast! thanks @bbgodfrey Nov 25 '16 at 8:17

Update: Another, much faster, alternative:

ClearAll[f0, f1]
f1 = Module[{m2 = Transpose[#][[{1, 3, 2, 4}]], us = UnitStep[#[[All, 1]] - .5]},
m2[[-1]] = Divide @@ m2[[{3, 2}]]; us Transpose[m2] + (1 - us) #] &;

f0 = # /. {z1_, z2_, z3_, _} /; z1 > 0.5 -> {z1, z3, z2, z2/z3} &;

f1@mat1


Equal @@ Through[{f0, f1}@mat1]


True

Timings:

results = {0, 0};
m1 = RandomReal[1, {1000000, 4}];
i = 1;
Grid[Transpose[{{"f0", "f1"}, First[AbsoluteTiming[results[[i++]]= #@m1;]]& /@{f0, f1}}],
Dividers -> All]


Original post:

If[# < .5, {##}, {#, #3, #2, #2/#3}] & @@@ mat1


Also:

mat2 = MapAt[Append[#[[{1, 3, 2}]], Divide @@ #[[{2, 3}]]] &, mat1,
List /@ Position[mat1[[All, 1]] - .5 , _?Positive]]