4
$\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$
1
  • 2
    $\begingroup$ Related: (3069) $\endgroup$
    – Mr.Wizard
    Jun 4, 2017 at 23:55

8 Answers 8

9
$\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$
1
  • $\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, 2017 at 11:48
4
$\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$
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$
3
$\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$
3
$\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$

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$
1
$\begingroup$
a = {{0.5, 1.2}, {0.75, 1.6}, {1.1, 4.3}, {1.3, 1.7}, {2.0, 3.2}};
b = {{0.5, 1.0}, {0.75, 1.9}, {1.1, 2.2}, {1.3, 0.7}, {2.0, 2.1}};

KeyValueMap[List] @ Merge[Apply @ Subtract] @ MapApply[Rule] @ Join[a, b]

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

This also functions if the two lists are unsorted:

b = RotateRight[b];

KeyValueMap[List] @ Merge[Apply @ Subtract] @ MapApply[Rule] @ Join[a, b]

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

$\endgroup$
0
$\begingroup$

Using Transpose and MapAt:

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

Transpose[#[[1]] & /@ MapAt[{#[[1]] - #[[2]]} &, Transpose[Transpose /@ b], {2}]]

(*{{0.5, 0.2}, {0.75, -0.3}, {1.1, 2.1}, {1.3, 1.}, {2., 1.1}}*)
$\endgroup$

This site is temporarily in read-only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .