2
$\begingroup$

We have two matrices list1 and list2 with identical first columns and a code written for subtracting the second columns. We should make a third matrix with the same first column and the second column equal to the difference between second columns of the original matrices. The code:

dif = ConstantArray[0, {Length@list1, 2}]
Do[

   j = list1[[;; , 1]][[i]];
   dif[[i, 2]] = list1[[;; , 2]][[i]] - list2[[;; , 2]][[i]];
   dif[[i, 1]] = j;

  , {i, 1, Length@list1}];

How can we use # to shorten the above code in an efficient way?

list1={{0.5,1.2},{0.75,1.6},{1.1,4.3},{1.3,1.7},{2.0,3.2}};
list2={{0.5,1.0},{0.75,1.9},{1.1,2.2},{1.3,0.7},{2.0,2.1}};
$\endgroup$
7
$\begingroup$

Based on an elegant method given by Mr Wizard (and originally posted as a comment):

list1 - list2.{{0, 0}, {0, 1}}

{0.5, 0.2}, {0.75, -0.3}, {1.1, 2.1}, {1.3, 1.}, {2., 1.1}}

Edit

This may be generalized somewhat:

list1 - list2.DiagonalMatrix[{0, 1}]

For

list3 = {{0.1, 10, 100, 1000}, {0.2, 20, 200, 2000}, {0.3, 30, 300, 
3000}, {0.4, 40, 400, 4000}, {0.5, 50, 500, 5000}};

list4 = {{0.1, 5, 50, 500}, {0.2, 10, 100, 1000}, {0.3, 15, 150, 
1500}, {0.4, 20, 200, 2000}, {0.5, 25, 250, 2500}};

Subtract all columns (of list4) except column 1:

list3 - list4.DiagonalMatrix[{0, 1, 1, 1}]

$$\left( \begin{array}{cccc} 0.1 & 5. & 50. & 500. \\ 0.2 & 10. & 100. & 1000. \\ 0.3 & 15. & 150. & 1500. \\ 0.4 & 20. & 200. & 2000. \\ 0.5 & 25. & 250. & 2500. \\ \end{array} \right)$$

Subtract columns 2 & 3, and subtract twice column 4:

list3 - list4.DiagonalMatrix[{0, 1, 1, 2}] // MatrixForm

$$\left( \begin{array}{cccc} 0.1 & 5. & 50. & 0. \\ 0.2 & 10. & 100. & 0. \\ 0.3 & 15. & 150. & 0. \\ 0.4 & 20. & 200. & 0. \\ 0.5 & 25. & 250. & 0. \\ \end{array} \right)$$

Edit 2

After this answer by Carl Woll:

Subtract all columns (of list4) except the first:

list3 - (list4 // #.SparseArray[{Band[{2, 2}] -> 1}, 
   Dimensions[#][[2]]] &) // MatrixForm

$$\left( \begin{array}{cccc} 0.1 & 5. & 50. & 500. \\ 0.2 & 10. & 100. & 1000. \\ 0.3 & 15. & 150. & 1500. \\ 0.4 & 20. & 200. & 2000. \\ 0.5 & 25. & 250. & 2500. \\ \end{array} \right)$$

Edit 3 Removed extraneous material to here

$\endgroup$
  • $\begingroup$ And, of course, as Dot may be considered a special case of Inner, list1 - Inner[Times, list2, {{0, 0}, {0, 1}}] $\endgroup$ – user1066 May 30 '17 at 11:48
4
$\begingroup$

Using MapThread

MapThread[{First[#1], Last[#1] - Last[#2]} &, {list1, list2}]

{{0.5, 0.2}, {0.75, -0.3}, {1.1, 2.1}, {1.3, 1.}, {2., 1.1}}

Using Transpose

Transpose@{list1[[;; , 1]], list1[[;; , 2]] - list2[[;; , 2]]}
$\endgroup$
4
$\begingroup$

Here is a timing comparison of the solutions proposed so far.

Initial setup:

n = 10^6;
list1 = RandomReal[1, {n, 2}];
list2 = list1;
list2[[All, 2]] = RandomReal[1, n];

Timings (obtained with Mathematica 8.0.4 on Windows 7 x64):

In[2]:= $Line = 0;
m1 = list1 - list2.{{0, 0}, {0, 1}}; // AbsoluteTiming // First
m2 = # {2, 1} & /@ list1 - list2; // AbsoluteTiming // First
m3 = list1 - ({0, 1} # & /@ list2); // AbsoluteTiming // First
m4 = Thread[{list1[[All, 1]], list1[[All, 2]] - list2[[All, 2]]}]; //  AbsoluteTiming // First
m5 = Thread[{#1 & @@@ list1, (#2 & @@@ list1) - (#2 & @@@ list2)}]; // AbsoluteTiming // First
m6 = MapThread[{First[#1], Last[#1] - Last[#2]} &, {list1, list2}]; // AbsoluteTiming // First
m7 = Transpose@{list1[[;; , 1]], list1[[;; , 2]] - list2[[;; , 2]]}; // AbsoluteTiming // First
☺ = {# & @@ #, # - #2 & @@ (#2 & @@@ {##})} & @@@ ({##}\[Transpose]) &; m8 = ☺[list1, list2]; // AbsoluteTiming // First
m9 = With[{cs1 = Complex @@@ list1, 
      cs2 = Composition[Conjugate, Complex] @@@ list2},
     Transpose@{Re[cs1], Im[cs1 + cs2]}]; // AbsoluteTiming // First
m1 == m2 == m3 == m4 == m5 == m6 == m7 == m8 == m9

Out[1]= 0.0930053
Out[2]= 0.3020172
Out[3]= 0.3110178
Out[4]= 0.4440253
Out[5]= 3.3061891
Out[6]= 4.9412827
Out[7]= 0.1540088
Out[8]= 11.7486720
Out[9]= 3.6802105
Out[10]= True

The absolute winner is elegant solution proposed by tomd in the comments:

list1 - list2.{{0, 0}, {0, 1}}

The second place belongs to the second solution by Anjan Kumar:

Transpose@{list1[[;; , 1]], list1[[;; , 2]] - list2[[;; , 2]]}
$\endgroup$
2
$\begingroup$
Thread[{list1[[All, 1]], list1[[All, 2]] - list2[[All, 2]]}]
(* {{0.5, 0.2}, {0.75, -0.3}, {1.1, 2.1}, {1.3, 1.}, {2., 1.1}} *)


Thread[{#1 & @@@ list1, (#2 & @@@ list1) - (#2 & @@@ list2)}]
(* {{0.5, 0.2}, {0.75, -0.3}, {1.1, 2.1}, {1.3, 1.}, {2., 1.1}} *)
$\endgroup$
2
$\begingroup$
list1 - ({0, 1} # & /@ list2)

{{0.5, 0.2}, {0.75, -0.3}, {1.1, 2.1}, {1.3, 1.}, {2., 1.1}}

Also:

☺ = {# & @@ #, # - #2 & @@ (#2 & @@@ {##})} & @@@ ({##}) &;

Mathematica graphics

☺[list1, list2]

{{0.5, 0.2}, {0.75, -0.3}, {1.1, 2.1}, {1.3, 1.}, {2., 1.1}}

$\endgroup$
2
$\begingroup$

In:

list1 = {{0.5, 1.2}, {0.75, 1.6}, {1.1, 4.3}, {1.3, 1.7}, {2.0, 3.2}};
list2 = {{0.5, 1.0}, {0.75, 1.9}, {1.1, 2.2}, {1.3, 0.7}, {2.0, 2.1}};

(*Method 1*)
cs1 = Complex @@@ list1 ;
cs2 = Conjugate @*Complex @@@ list2;
Transpose@{Re[cs1], Im[cs1 + cs2]}

(*Method 2*)
 # {2, 1} & /@ list1 - list2

Out:

{{0.5, 0.2}, {0.75, -0.3}, {1.1, 2.1}, {1.3, 1.}, {2., 1.1}}
{{0.5, 0.2}, {0.75, -0.3}, {1.1, 2.1}, {1.3, 1.}, {2., 1.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.