13

Consider a table

tab = Table[{i,i^2,i^3,i^5,i^0.3,i^0.7},{i,0.2,3,0.1}];

I would like to multiply the 2rd and 5rd columns by some number. This is how I do it:

a = 2
{#[[1]],a*#[[2]],#[[3]],#[[4]],a*#[[5]],#[[6]]}&/@tab

However, such syntax becomes really annoying if the table would have many columns:

{...,a*#[[K]],...,a*#[[M]],...}&/@tab

where K,M are some numbers. How can I multiply the columns in a more compact way? I.e., what is an analog of ... in Mathematica?

Peter Mortensen
  • 759
  • 4
  • 7
John Taylor
  • 5,701
  • 2
  • 12
  • 33

6 Answers6

19

Another option could be

a*tab[[All, {2, 5}]]

Which will multiply columns 2 and 5 by a. To replace the original matrix just do

tab[[All, {2, 5}]] = a*tab[[All, {2, 5}]];
Nasser
  • 143,286
  • 11
  • 154
  • 359
18

The simplest method I can think off, is with Query:

Query[All, Thread[{2, 5} -> Function[a * #]]] @ tab
Sjoerd Smit
  • 23,370
  • 46
  • 75
  • 2
    (+1, days ago!) It appears that in this case Query 'compiles' into a right-composition of the operator form of MapAt: Query[All, Thread[{2,5} -> Function[a * #]]]//Normal (* MapAt[a*#1 & , {All, 5}] /* MapAt[a*#1 & , {All, 2}] *) – user1066 Jun 10 '22 at 14:06
11

Using the Dot product:

tab.DiagonalMatrix[{1,2,1,1,2,1}]

Or, if there are a lot of columns:

Edit

Lucas Lang suggested a neat modification, such as the following, to the original SparseArray answer (and thanks!):

tab.DiagonalMatrix[SparseArray[Thread[{2,5}->2], {6},1]]

Original answer

tab.SparseArray[{{2,2}->2, {5,5}-> 2,Band[{1, 1}] -> 1}, {6,6}]

With Inner:

Inner[Times, tab, {1,2,1,1,2,1}, List]

In addition, if the table consists of only two columns (a table of {x,y} values, maybe) and if it is desired to multiply all y-values by 2:

table.{{1,0},{0,2}}

For example:

tab[[All,;;2]].{{1,0},{0,2}}

Modify in place using ApplyTo (//=)

(modify tab, not a copy)

tab[[All,{2,5}]]//= 2#&

or using the new function syntax:

tab[[;;,{2,5}]]//=(x |-> 2 x)

Edit 2: ReplaceAt

Since v13.1,ReplaceAt may be used:

result = ReplaceAt[tab,x_ :> 2 x, {All,{2,5}}];

result == tab.DiagonalMatrix[{1,2,1,1,2,1}]

(* True *)

Edit 3: Threaded

As kglr has taught us (see here and here), an even more convenient method is arguably with Threaded

want = tab.DiagonalMatrix[{1,2,1,1,2,1}];

tab Threaded[{1,2,1,1,2,1}] == want

tab Threaded[SparseArray[Thread[{2,5}->2],6,1]] == want

(* True ) ( True *)

A further example:

myTable = Array[Subscript[a, Row[{##}]] &, {3, 6}];
myTable//TeXForm

$$ \left( \begin{array}{cccccc} a_{11} & a_{12} & a_{13} & a_{14} & a_{15} & a_{16} \\ a_{21} & a_{22} & a_{23} & a_{24} & a_{25} & a_{26} \\ a_{31} & a_{32} & a_{33} & a_{34} & a_{35} & a_{36} \\ \end{array} \right) $$

myTable Threaded[SparseArray[Thread[{2,5}->2],Dimensions@myTable[[2]],1]]

$$ \left( \begin{array}{cccccc} a_{11} & 2 a_{12} & a_{13} & a_{14} & 2 a_{15} & a_{16} \\ a_{21} & 2 a_{22} & a_{23} & a_{24} & 2 a_{25} & a_{26} \\ a_{31} & 2 a_{32} & a_{33} & a_{34} & 2 a_{35} & a_{36} \\ \end{array} \right) $$

myTable Threaded[SparseArray[{2->2,3->10,6->100},Dimensions@myTable[[2]],1]]

$$ \left( \begin{array}{cccccc} a_{11} & 2 a_{12} & 10 a_{13} & a_{14} & a_{15} & 100 a_{16} \\ a_{21} & 2 a_{22} & 10 a_{23} & a_{24} & a_{25} & 100 a_{26} \\ a_{31} & 2 a_{32} & 10 a_{33} & a_{34} & a_{35} & 100 a_{36} \\ \end{array} \right) $$

user1066
  • 17,923
  • 3
  • 31
  • 49
  • 2
    You could also use a 1D SparseArray with default value 1, and then use DiagonalMatrix to convert it. That way you can avoid the 2D specifications and the need for Band – Lukas Lang Jun 08 '22 at 11:08
5
a = 2; k = 2; m = 5;

Using direct multiplication:

v = ReplacePart[ConstantArray[1, Last@Dimensions@tab], 
  List /@ {k, m} -> a]

{1, 2, 1, 1, 2, 1}

v tab[[#]] & /@ Range[Length@tab] // TableForm

Using MapAt:

MapAt[Times[a #] &, tab, {All, #} & /@ {k, m}] // TableForm

Using SubsetMap:

SubsetMap[Times[a #] &, tab[[#]], {k, m}] & /@ 
  Range[Length@tab] // TableForm
Syed
  • 52,495
  • 4
  • 30
  • 85
1
MapAt[a*#&,tab,{{All,2},{All,5}}]
lericr
  • 27,668
  • 1
  • 18
  • 64
1

Building a MultiplyByPosition function:

MultiplyByPosition[array_?VectorQ, factor_, positions : {___Integer}] := 
ReplacePart[array, Thread[Rule[Nest[Map[List, #] &, positions, 2], 
Flatten[factor*Extract[array, Nest[Map[List, #] &, positions, 2]]]]]]

MultiplyByPosition[array_?TensorQ, factor_, positions : {___Integer}] := Map[MultiplyByPosition[#, factor, positions] &, array]

Testing MultiplyByPosition:

MultiplyByPosition[tab, a, {2, 5}]===Query[All, Thread[{2, 5} -> Function[a*#]]]@tab

(True)

Another way using ReplaceAt and SubsetMap:

Transpose@ReplaceAt[{Transpose@tab}, _ -> SubsetMap[a*# &, {2, 5}], 0]

enter image description here

E. Chan-López
  • 23,117
  • 3
  • 21
  • 44